Flask Blog Favorites Admin
## Favorites Function and Backend Management
In this chapter, you will learn to implement the favorites function using many-to-many relationships, and quickly build a backend management system using Flask-Admin.
* * *
## Many-to-Many Relationship Design
Favorites function requirements: A user can favorite multiple articles, and an article can be favorited by multiple users.
In SQLAlchemy, many-to-many relationships are implemented through an Association Table.
## Example
# File path: models.py - Add association table and modify Post model
from datetime import datetime
# Association table: No need to define as a model class, use db.Table directly
favorites = db.Table('favorites',
db.Column('user_id', db.Integer, db.ForeignKey('users.id'), primary_key=True),
db.Column('post_id', db.Integer, db.ForeignKey('posts.id'), primary_key=True),
db.Column('created_at', db.DateTime, default=datetime.utcnow)
)
class Post(db.Model):
__tablename__ ='posts'
# ... existing fields remain unchanged ...
Then execute the migration:
(venv) $ flask db migrate -m "Add favorites association table"
(venv) $ flask db upgrade
* * *
## Favorites Toggle View
## Example
# File path: app/blueprints/user.py (new file)
from flask import Blueprint, render_template, redirect, url_for, request, flash
from flask_login import login_required, current_user
from app.models import Post, db, favorites
user_bp = Blueprint('user', __name__)
@user_bp.route("/favorite/", methods=['POST'])
@login_required
def toggle_favorite(post_id):
"""Toggle favorite status"""
post = Post.query.get_or_404(post_id)
# Check if already favorited: query if this user-article combination exists in the association table
is_faved = db.session.query(favorites).filter(
favorites.c.user_id== current_user.id,
favorites.c.post_id== post.id
).first()is not None
if is_faved:
# Remove from favorites
db.session.execute(
favorites.delete().where(
(favorites.c.user_id== current_user.id)&
(favorites.c.post_id== post.id)
)
)
db.session.commit()
flash(f'Unfavorited γ{post.title}γ','info')
else:
# Add to favorites
db.session.execute(
favorites.insert().values(user_id=current_user.id, post_id=post.id)
)
db.session.commit()
flash(f'Favorited γ{post.title}γ','success')
return redirect(request.referrer or url_for('main.index'))
@user_bp.route("/favorites")
@login_required
def favorites_list():
"""Current user's favorites list"""
# Query user's favorited articles through the association table
faved_posts = Post.query.join(
favorites,(favorites.c.post_id== Post.id)
).filter(
favorites.c.user_id== current_user.id
).order_by(favorites.c.created_at.desc()).all()
return render_template('favorites.html', posts=faved_posts)
### Register Blueprint in app.py
## Example
from app.blueprints.user import user_bp
app.register_blueprint(user_bp)
* * *
## Add Favorite Button on Detail Page and List Page
## Example
{% if current_user.is_authenticated %}
{% endif %}
> Favorite operation uses POST request (form submission), not GET link. GET requests should not produce side effects (modify database), which is a basic principle of web development.
* * *
## Flask-Admin β Backend Management
Flask-Admin is an extension in the Flask ecosystem that corresponds to Django Admin.
After configuration, you can manage articles and category data in the browser.
(venv) $ pip install flask-admin
## Example
# File path: app.py or new admin_setup.py
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from app.models import Post, Category, User
# Custom ModelView: Control which fields are displayed in the backend
class PostAdmin(ModelView):
column_list =['title','category','created_at','updated_at']
column_searchable_list =['title','summary']
column_filters =['category','created_at']
form_columns =['title','slug','summary','content','category']
class CategoryAdmin(ModelView):
column_list =['name','slug']
form_columns =['name','slug']
# Create Admin instance
admin = Admin(app, name='TUTORIAL Blog Backend
YouTip