cloudKe's profile picture

Modifying Routes for Session-Based Post IDs

Here's how to modify your existing routes to use session-based post IDs instead of sequential integers: Updated routes.py

import os import time 

import uuid from datetime 

import datetime from flask 

import (render_template, url_for, flash, redirect, request, abort, Blueprint, jsonify, current_app, session) 

from flask_login import current_user, login_required from werkzeug.utils 

import secure_filename from flaskblog import db from flaskblog.models 

import Post from flaskblog.posts.forms import PostForm posts = Blueprint('posts', __name__) # Allowed image extensions ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} def allowed_file(filename):    return '.' in filename and \           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS def generate_post_id():    """Generate a unique post ID combining session ID and timestamp"""    if 'session_id' not in session:        session['session_id'] = str(uuid.uuid4())    return f"{session['session_id']}-{datetime.now().timestamp()}" @posts.route("/post/new", methods=['GET', 'POST']) @login_required def new_post():    form = PostForm()    if form.validate_on_submit():        # Generate session-based post ID        post_id = generate_post_id()                # Get the content from the form (CKEditor will have updated it)        content = request.form.get('content')        post = Post(            id=post_id,            title=form.title.data,            content=content,            author=current_user        )        db.session.add(post)        db.session.commit()        flash('Your post has been created!', 'success')        return redirect(url_for('main.home'))    return render_template('create_post.html', title='New Post',                         form=form, legend='New Post') @posts.route("/post/<string:post_id>") def post(post_id):    post = Post.query.get_or_404(post_id)    return render_template('post.html', title=post.title, post=post) @posts.route("/post/<string:post_id>/update", methods=['GET', 'POST']) @login_required def update_post(post_id):    post = Post.query.get_or_404(post_id)    if post.author != current_user:        abort(403)    form = PostForm()    if form.validate_on_submit():        post.title = form.title.data        post.content = form.content.data        db.session.commit()        flash('Your post has been updated!', 'success')        return redirect(url_for('posts.post', post_id=post.id))    elif request.method == 'GET':        form.title.data = post.title        form.content.data = post.content    return render_template('create_post.html', title='Update Post',                         form=form, legend='Update Post') @posts.route("/post/<string:post_id>/delete", methods=['POST']) @login_required def delete_post(post_id):    post = Post.query.get_or_404(post_id)    if post.author != current_user:        abort(403)    db.session.delete(post)    db.session.commit()    flash('Your post has been deleted!', 'success')    return redirect(url_for('main.home')) @posts.route('/upload-image', methods=['POST']) @login_required def upload_image():    """Handle image uploads from CKEditor"""    if 'upload' not in request.files:        return jsonify({'error': {'message': 'No file uploaded'}}), 400        file = request.files['upload']        if file.filename == '':        return jsonify({'error': {'message': 'No selected file'}}), 400        if file and allowed_file(file.filename):        # Create upload folder if it doesn't exist        upload_folder = os.path.join(current_app.root_path, 'static/post_images')        os.makedirs(upload_folder, exist_ok=True)                # Generate unique filename        timestamp = str(int(time.time()))        filename = f"{current_user.id}_{timestamp}_{secure_filename(file.filename)}"        filepath = os.path.join(upload_folder, filename)        file.save(filepath)                return jsonify({            'url': url_for('static', filename=f'post_images/{filename}', _external=True)        })        return jsonify({'error': {'message': 'Allowed file types: png, jpg, jpeg, gif'}}), 400

Required Model Changes

You'll need to modify your Post model to use String IDs instead of Integer IDs:

python

 

from flaskblog import db class Post(db.Model):    id = db.Column(db.String(100), primary_key=True)  # Changed from Integer to String    title = db.Column(db.String(100), nullable=False)    content = db.Column(db.Text, nullable=False)    date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)    author = db.relationship('User', backref=db.backref('posts', lazy=True))    def __repr__(self):        return f"Post('{self.title}', '{self.date_posted}')"

Migration Steps

  1. Create a migration to change the Post ID type:

    bash

     

  2. flask db migrate -m "Change post id to string" flask db upgrade
  3. Update templates to handle string IDs instead of integers (most templates won't need changes, but any that assume integer IDs will need updating)

Key Changes Made:

  1. Changed route parameters from <int:post_id> to <string:post_id>
  2. Added generate_post_id() function to create session-based IDs
  3. Modified the Post model to use String ID instead of Integer
  4. Updated the new_post route to use the generated ID
  5. Kept all other functionality (image uploads, etc.) the same

Advantages of This Approach:

  1. Session-based IDs provide better privacy (don't reveal total post count)
  2. No ID collisions between different users' posts
  3. Maintains all existing functionality including image uploads and CKEditor integration
  4. Works with Flask-Login while adding session-based features

Note: If you need to maintain backward compatibility with existing integer IDs, you could implement a hybrid approach that supports both types of IDs.

0 comments

Comments (0)

Login to post a comment