Fastapi 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 use sqladmin to build a backend management system.
* * *
## Many-to-Many Relationship Design
## Instance
# File path: models.py Add association table and modify Post model
from sqlalchemy import Table
# Association table: Many-to-many intermediate table for User and Post
favorites = Table(
"favorites",
Base.metadata,
Column("user_id", Integer, ForeignKey("users.id"), primary_key=True),
Column("post_id", Integer, ForeignKey("posts.id"), primary_key=True),
Column("created_at", DateTime, default=datetime.utcnow)
)
Execute migration:
(venv) $ alembic revision --autogenerate -m "Add Favorite Association Table"(venv) $ alembic upgrade head
* * *
## Favorites and Unfavorites Routes
## Instance
# File path: routers/favorites.py
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from database import get_db
from models import Post, favorites
from routers.users import get_current_user
from fastapi.templating import Jinja2Templates
router = APIRouter(prefix="/favorites", tags=)
templates = Jinja2Templates(directory="templates")
@router.post("/toggle/{post_id}")
def toggle_favorite(
post_id: int,
request: Request,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)# Need login
):
"""Toggle favorite status"""
post = db.query(Post).filter(Post.id== post_id).first()
if not post:
raise HTTPException(status_code=404, detail="Post not found")
# Check if already favorited
is_faved = db.query(favorites).filter(
favorites.c.user_id== current_user.id,
favorites.c.post_id== post.id
).first()is not None
if is_faved:
# Unfavorite
db.execute(
favorites.delete().where(
(favorites.c.user_id== current_user.id)&
(favorites.c.post_id== post.id)
)
)
db.commit()
else:
# Add to favorites
db.execute(
favorites.insert().values(user_id=current_user.id, post_id=post.id)
)
db.commit()
from fastapi.responses import RedirectResponse
return RedirectResponse(url=request.headers.get("referer","/"), status_code=303)
@router.get("/", name="favorites_list")
def favorites_list(
request: Request,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""My favorites list"""
faved_posts = db.query(Post).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 templates.TemplateResponse("favorites.html",{
"request": request,
"posts": faved_posts
})
* * *
## Add Favorite Button to Detail Page
## Instance
* * *
## sqladmin β Backend Management
sqladmin is a backend management extension in the FastAPI ecosystem, comparable to Django Admin.
It is specifically designed for SQLAlchemy and integrates seamlessly with FastAPI.
(venv) $ pip install sqladmin
## Instance
# File path: main.py Configure sqladmin
from sqladmin import Admin, ModelView
from database import engine
from models import Post, Category, User
class PostAdmin(ModelView, model=Post):
column_list =[Post.id, Post.title, Post.category, Post.created_at]
column_searchable_list =[Post.title, Post.summary]
column_sortable_list =[Post.created_at, Post.title]
form_columns =[Post.title, Post.slug, Post.summary, Post.content, Post.category_id]
class CategoryAdmin(ModelView, model=Category):
column_list =[Category.id, Category.name, Category.slug]
form_columns =[Category.name, Category.slug]
class UserAdmin(ModelView, model=User):
column_list =[User.id, User.username, User.email]
column_searchable_list =[User.username, User.email]
# Do not display password field (security consideration)
form_excluded_columns =[User.hashed_password]
# Create Admin instance, bind to FastAPI app
admin = Admin(app, engine, title="TUTORIAL Blog Admin")
admin.add_view(PostAdmin)
admin.add_view(CategoryAdmin)
admin.add_view(UserAdmin)
Access /admin to enter the backend management interface.
### sqladmin vs Flask-Admin vs Django Admin
| Feature | Django Admin | Flask-Admin | sqladmin |
| --- | --- | --- | --- |
| Registration method | admin.site.register() | admin.add_view(ModelView()) | Admin + add_view |
| ORM support | Django ORM | SQLAlchemy / MongoEngine | SQLAlchemy (only) |
| Authentication support | Built-in | Need manual integration | Built-in authentication_backend |
| Async support | Not supported | Not supported | Native async |
> sqladmin does not require login by default. In production environment, you need to configure `authentication_backend` to add authentication protection. For details, refer to the official sqladmin documentation.
* * *
## Chapter Summary
In this chapter, you implemented two important functions: using Table association table to implement many-to-many relationship for favorites; using sqladmin to quickly build a backend management system.
Now the blog's user interaction (registration, login, favorites) and management functions (Admin backend) are complete.
YouTip