框架对比
特性 FastAPI Django Flask
架构风格 现代异步API优先 全功能MVC框架 微框架+扩展
开发速度 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐
性能 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
学习曲线 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
内置功能 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐
灵活性 ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐
文档生成 自动Swagger 需要第三方 需要手动
适用场景 高性能API、微服务 全功能Web应用、内容管理 灵活定制、原型开发
FastAPI:新建的微服务、高性能API、AI服务集成
Django:传统企业应用、需要快速开发全功能系统
Flask:需要高度定制化、轻量级服务、现有系统扩展
业务场景:企业级用户权限管理系统
功能需求:
- 用户注册、登录、JWT认证
- 角色权限管理(管理员、普通用户)
- 用户信息CRUD操作
- 数据验证和错误处理
- 数据库操作和事务管理
1. FastAPI 实现
- 依赖注入系统:Depends() 用于管理数据库连接、认证等依赖
- Pydantic模型验证:自动请求数据验证和序列化
- 自动API文档:访问 /docs 获得交互式Swagger文档
- 异步支持:原生支持async/await
- 类型提示:完整的Python类型提示,提升代码可维护性
- OpenAPI标准:自动生成符合OpenAPI规范的文档
text
fastapi_project/
├── main.py
├── models.py
├── schemas.py
├── auth.py
├── database.py
└── requirements.txt
python
from fastapi import FastAPI,Depends,HTTPException,status
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from typing import List
import auth
import models
import schemas
from database import SessionLocal,engine
#创建数据库表
models.Base.metadata.create_all(bind=engine)
app = FastAPI(title="用户权限管理系统",version="1.0.0")
#CORS中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
#数据库依赖
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
#路由定义
@app.post("/register",response_model=schemas.UserResponse)
async def register(user:chemas.UserCreate,db:Session=Depends(get_db)):
"""用户注册"""
#检查用户是否存在
db_user = db.query(models.User).filter(models.User.email == user.email).first()
if db_user:
raise HTTPException(status_code=400,detail="邮箱已注册")
#创建用户
hashed_password = auth.get_password_hash(user.password)
db_user = models.User(
username=user.username,
email=user.email,
hashed_password=hashed_password,
role=user.role
)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
@app.post("/login")
async def login(from_data:schemas.UserLogin,db:Session=Depends(get_db)):
"""用户登录"""
user = auth.authenticate_user(db, form_data.email, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="邮箱或密码错误",
)
access_token = auth.create_access_token(data={"sub": user.email})
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me", response_model=schemas.UserResponse)
async def read_users_me(
current_user: models.User = Depends(auth.get_current_active_user)
):
"""获取当前用户信息"""
return current_user
@app.get("/users", response_model=List[schemas.UserResponse])
async def read_users(
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
current_user: models.User = Depends(auth.get_current_active_user)
):
"""获取用户列表(需要管理员权限)"""
if current_user.role != "admin":
raise HTTPException(status_code=403, detail="权限不足")
users = db.query(models.User).offset(skip).limit(limit).all()
return users
@app.put("/users/{user_id}", response_model=schemas.UserResponse)
async def update_user(
user_id: int,
user_update: schemas.UserUpdate,
db: Session = Depends(get_db),
current_user: models.User = Depends(auth.get_current_active_user)
):
"""更新用户信息"""
# 权限检查:管理员或用户自己
if current_user.role != "admin" and current_user.id != user_id:
raise HTTPException(status_code=403, detail="权限不足")
db_user = db.query(models.User).filter(models.User.id == user_id).first()
if not db_user:
raise HTTPException(status_code=404, detail="用户不存在")
# 更新字段
update_data = user_update.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(db_user, field, value)
db.commit()
db.refresh(db_user)
return db_user
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
schemas.py (Pydantic模型)
python
# schemas.py (Pydantic模型)
from pydantic import BaseModel, EmailStr
from typing import Optional
class UserBase(BaseModel):
username: str
email: EmailStr
role: str = "user"
class UserCreate(UserBase):
password: str
class UserLogin(BaseModel):
email: EmailStr
password: str
class UserUpdate(BaseModel):
username: Optional[str] = None
email: Optional[EmailStr] = None
role: Optional[str] = None
class UserResponse(UserBase):
id: int
class Config:
orm_mode = True
models.py (SQLAlchemy模型)
python
# models.py (SQLAlchemy模型)
from sqlalchemy import Column, Integer, String, Boolean
from database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(50), unique=True, index=True)
email = Column(String(100), unique=True, index=True)
hashed_password = Column(String(100))
role = Column(String(20), default="user")
is_active = Column(Boolean, default=True)
2. Django 实现
- Django ORM:强大的对象关系映射,自动数据库迁移
- Django REST Framework:成熟的REST API框架,提供序列化、视图集等
- Admin后台:自动生成管理界面,快速进行数据管理
- 认证权限系统:内置完善的用户认证和权限管理
- 中间件支持:请求/响应处理的中间件管道
- 信号机制:解耦的事件处理系统
text
django_project/
├── manage.py
├── requirements.txt
└── user_system/
├── __init__.py
├── settings.py
├── urls.py
├── wsgi.py
└── users/
├── __init__.py
├── admin.py
├── apps.py
├── models.py
├── serializers.py
├── views.py
├── urls.py
└── permissions.py
python
# users/urls.py
from django.urls import path
from rest_framework_simplejwt.views import TokenRefreshView
from . import views
urlpatterns = [
path('register/', views.UserRegisterView.as_view(), name='register'),
path('login/', views.user_login, name='login'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('users/', views.UserListView.as_view(), name='user-list'),
path('users/<int:pk>/', views.UserDetailView.as_view(), name='user-detail'),
path('me/', views.UserDetailView.as_view(), name='user-me'),
]
python
# users/views.py
from rest_framework import status,generics,permissions
from rest_framework.decorators import api_view,permission_classes
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth import login
from .models import User
from .serializers import UserSerializer, UserRegisterSerializer, UserLoginSerializer
from .permissions import IsAdminUser, IsOwnerOrAdmin
class UserRegisterView(generics.CreateAPIView):
queryset = User.objects.all()
serializer_class = UserRegisterSerializer
permission_classes = [permissions.AllowAny]
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
# 生成JWT token
refresh = RefreshToken.for_user(user)
return Response({
'user': UserSerializer(user).data,
'refresh': str(refresh),
'access': str(refresh.access_token),
}, status=status.HTTP_201_CREATED)
@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def user_login(request):
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
user = serializer.validated_data['user']
refresh = RefreshToken.for_user(user)
return Response({
'user': UserSerializer(user).data,
'refresh': str(refresh),
'access': str(refresh.access_token),
})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdminUser]
class UserDetailView(generics.RetrieveUpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsOwnerOrAdmin]
python
# users/permissions.py
from rest_framework import permissions
class IsAdminUser(permissions.BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticated and request.user.role == 'admin'
class IsOwnerOrAdmin(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return request.user and (request.user.role == 'admin' or obj == request.user)
python
# users/serializers.py
from rest_framework import serializers
from django.contrib.auth import authenticate
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'username', 'role', 'date_joined')
read_only_fields = ('id', 'date_joined')
class UserRegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, min_length=6)
class Meta:
model = User
fields = ('email', 'username', 'password', 'role')
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class UserLoginSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField()
def validate(self, data):
email = data.get('email')
password = data.get('password')
if email and password:
user = authenticate(email=email, password=password)
if not user:
raise serializers.ValidationError('邮箱或密码错误')
if not user.is_active:
raise serializers.ValidationError('用户已被禁用')
data['user'] = user
else:
raise serializers.ValidationError('必须提供邮箱和密码')
return data
python
# users/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.utils import timezone
class UserManager(BaseUserManager):
def create_user(self, email, username, password=None, role='user'):
if not email:
raise ValueError('用户必须提供邮箱')
user = self.model(
email=self.normalize_email(email),
username=username,
role=role,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(
email=email,
username=username,
password=password,
role='admin'
)
return user
class User(AbstractBaseUser):
ROLE_CHOICES = [
('admin', '管理员'),
('user', '普通用户'),
]
email = models.EmailField(unique=True, verbose_name='邮箱')
username = models.CharField(max_length=50, unique=True, verbose_name='用户名')
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user', verbose_name='角色')
is_active = models.BooleanField(default=True, verbose_name='是否激活')
date_joined = models.DateTimeField(default=timezone.now, verbose_name='注册时间')
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
class Meta:
verbose_name = '用户'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
@property
def is_staff(self):
return self.role == 'admin'
def has_perm(self, perm, obj=None):
return self.role == 'admin'
def has_module_perms(self, app_label):
return self.role == 'admin'
3. Flask 实现
- 蓝图组织:使用Blueprint模块化组织路由
- 装饰器模式:灵活的装饰器用于认证、验证、权限控制
- 扩展生态:Flask-SQLAlchemy、Flask-Migrate、Flask-JWT-Extended等
- 显式控制:对请求处理流程有完全的控制权
- 灵活性:可以自由选择组件和架构模式
text
flask_project/
├── app.py
├── config.py
├── models.py
├── routes/
│ ├── __init__.py
│ ├── auth.py
│ └── users.py
├── utils/
│ ├── __init__.py
│ └── decorators.py
└── requirements.txt
python
# app.py
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_jwt_extended import JWTManager
from config import Config
import os
db = SQLAlchemy()
migrate = Migrate()
jwt = JWTManager()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
# 初始化扩展
db.init_app(app)
migrate.init_app(app, db)
jwt.init_app(app)
# 注册蓝图
from routes.auth import auth_bp
from routes.users import users_bp
app.register_blueprint(auth_bp, url_prefix='/api/auth')
app.register_blueprint(users_bp, url_prefix='/api')
# 错误处理
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': '资源未找到'}), 404
@app.errorhandler(500)
def internal_error(error):
return jsonify({'error': '服务器内部错误'}), 500
return app
if __name__ == '__main__':
app = create_app()
app.run(debug=True)
python
# models.py
from app import db
from werkzeug.security import generate_password_hash, check_password_hash
from flask_jwt_extended import create_access_token
from datetime import datetime
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True, nullable=False)
email = db.Column(db.String(120), unique=True, index=True, nullable=False)
password_hash = db.Column(db.String(128))
role = db.Column(db.String(20), default='user')
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def to_dict(self):
return {
'id': self.id,
'username': self.username,
'email': self.email,
'role': self.role,
'is_active': self.is_active,
'created_at': self.created_at.isoformat()
}
def generate_token(self):
return create_access_token(identity=self.id)
@staticmethod
def verify_token(token):
from flask_jwt_extended import decode_token
try:
data = decode_token(token)
return User.query.get(data['identity'])
except:
return None
python
# routes/auth.py
from flask import Blueprint, request, jsonify
from app import db
from models import User
from utils.decorators import validate_json
import json
auth_bp = Blueprint('auth', __name__)
@auth_bp.route('/register', methods=['POST'])
@validate_json({
'type': 'object',
'properties': {
'username': {'type': 'string', 'minLength': 3},
'email': {'type': 'string', 'format': 'email'},
'password': {'type': 'string', 'minLength': 6},
'role': {'type': 'string', 'enum': ['user', 'admin']}
},
'required': ['username', 'email', 'password']
})
def register():
data = request.get_json()
# 检查用户是否存在
if User.query.filter_by(email=data['email']).first():
return jsonify({'error': '邮箱已注册'}), 400
if User.query.filter_by(username=data['username']).first():
return jsonify({'error': '用户名已存在'}), 400
# 创建用户
user = User(
username=data['username'],
email=data['email'],
role=data.get('role', 'user')
)
user.set_password(data['password'])
db.session.add(user)
db.session.commit()
token = user.generate_token()
return jsonify({
'user': user.to_dict(),
'access_token': token
}), 201
@auth_bp.route('/login', methods=['POST'])
@validate_json({
'type': 'object',
'properties': {
'email': {'type': 'string', 'format': 'email'},
'password': {'type': 'string'}
},
'required': ['email', 'password']
})
def login():
data = request.get_json()
user = User.query.filter_by(email=data['email']).first()
if not user or not user.check_password(data['password']):
return jsonify({'error': '邮箱或密码错误'}), 401
if not user.is_active:
return jsonify({'error': '用户已被禁用'}), 401
token = user.generate_token()
return jsonify({
'user': user.to_dict(),
'access_token': token
})
python
# routes/users.py
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from app import db
from models import User
from utils.decorators import admin_required, validate_json
users_bp = Blueprint('users', __name__)
@users_bp.route('/users', methods=['GET'])
@jwt_required()
@admin_required
def get_users():
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 10, type=int)
users = User.query.paginate(
page=page, per_page=per_page, error_out=False
)
return jsonify({
'users': [user.to_dict() for user in users.items],
'total': users.total,
'pages': users.pages,
'current_page': page
})
@users_bp.route('/users/<int:user_id>', methods=['GET', 'PUT'])
@jwt_required()
def user_detail(user_id):
current_user_id = get_jwt_identity()
user = User.query.get_or_404(user_id)
# 权限检查
if current_user_id != user_id and User.query.get(current_user_id).role != 'admin':
return jsonify({'error': '权限不足'}), 403
if request.method == 'GET':
return jsonify({'user': user.to_dict()})
elif request.method == 'PUT':
data = request.get_json()
# 更新字段
if 'username' in data:
user.username = data['username']
if 'email' in data:
user.email = data['email']
if 'role' in data and User.query.get(current_user_id).role == 'admin':
user.role = data['role']
db.session.commit()
return jsonify({'user': user.to_dict()})
@users_bp.route('/me', methods=['GET'])
@jwt_required()
def get_current_user():
user_id = get_jwt_identity()
user = User.query.get_or_404(user_id)
return jsonify({'user': user.to_dict()})
python
# utils/decorators.py
from functools import wraps
from flask import request, jsonify
from flask_jwt_extended import get_jwt_identity
from app import db
from models import User
import jsonschema
from jsonschema import validate
def validate_json(schema):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not request.is_json:
return jsonify({'error': '请求必须是JSON格式'}), 400
try:
data = request.get_json()
validate(instance=data, schema=schema)
except jsonschema.ValidationError as e:
return jsonify({'error': f'数据验证失败: {e.message}'}), 400
except Exception as e:
return jsonify({'error': '无效的JSON数据'}), 400
return f(*args, **kwargs)
return decorated_function
return decorator
def admin_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
current_user_id = get_jwt_identity()
user = User.query.get(current_user_id)
if not user or user.role != 'admin':
return jsonify({'error': '需要管理员权限'}), 403
return f(*args, **kwargs)
return decorated_function