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
Create a migration to change the Post ID type:
bash
- flask db migrate -m "Change post id to string" flask db upgrade
- 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:
- Changed route parameters from <int:post_id> to <string:post_id>
- Added generate_post_id() function to create session-based IDs
- Modified the Post model to use String ID instead of Integer
- Updated the new_post route to use the generated ID
- Kept all other functionality (image uploads, etc.) the same
Advantages of This Approach:
- Session-based IDs provide better privacy (don't reveal total post count)
- No ID collisions between different users' posts
- Maintains all existing functionality including image uploads and CKEditor integration
- 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.
Comments (0)
Login to post a comment