Python后端框架:FastAPI+Django+Flask

框架对比

特性 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

main.py

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

urls.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'),
]

views.py

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]	

permissions.py

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)

serializers.py

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

models.py

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

app.py

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)

models.py

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

auth.py

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
    })

users.py

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()})

decorators.py

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
相关推荐
蒋星熠4 小时前
实证分析:数据驱动决策的技术实践指南
大数据·python·数据挖掘·数据分析·需求分析
独行soc5 小时前
2025年渗透测试面试题总结-250(题目+回答)
网络·驱动开发·python·安全·web安全·渗透测试·安全狮
一晌小贪欢5 小时前
Pandas操作Excel使用手册大全:从基础到精通
开发语言·python·自动化·excel·pandas·办公自动化·python办公
IT痴者7 小时前
《PerfettoSQL 的通用查询模板》---Android-trace
android·开发语言·python
谅望者9 小时前
数据分析笔记14:Python文件操作
大数据·数据库·笔记·python·数据挖掘·数据分析
l1t9 小时前
调用python函数的不同方法效率对比测试
开发语言·数据库·python·sql·duckdb
2501_941111409 小时前
使用Scrapy框架构建分布式爬虫
jvm·数据库·python
今天吃饺子9 小时前
如何用MATLAB调用python实现深度学习?
开发语言·人工智能·python·深度学习·matlab
萧鼎9 小时前
Python Mahotas 图像处理库:高性能计算机视觉工具
图像处理·python·计算机视觉