从 FastAPI 到 Django Ninja:现代 Python Web 框架的探索与实践
工作多年,Python WEb框架从 Django、Flask、Tornado 到后来 python 支持异步后的 Sanic 都在项目上使用过,甚至还短暂涉猎过Trypyramid。 不过兜兜转转还是回到Django的怀抱,因为它在搭建业务 API 时的高效性,尤其是结合 django-rest-framework。 用其他框架基础功能还需要自行搭建,而且数据库 ORM 框架只能选择 SQLAlchemy,说实话 SQLAlchemy 差 Django的还是很多的。
最近打算做一个AI平台,现在大模型对话一般都用流式传输,流式传输在异步框架中具有天然优势。 而且看网上的例子也都是使用fastapi,所以一开始技术选型使用fastapi。fastapi宣传高性能(Async)、标准化(OpenAPI)、类型声明(Pydantic)。
使用 fastapi 搭建
项目结构如下
fastapi_app/
│── main.py # 入口文件,创建 FastAPI 应用
│── routers/
│ ├── __init__.py
│ ├── home.py # 主页路由
│ ├── users.py # 用户相关路由
│── core/
│ ├── __init__.py
│ ├── middlewares.py # 自定义中间件
│ ├── logger.py # 日志模块
│ ├── db.py # 数据库连接
│ ├── event.py # 生命周期事件
│ ├── config.py # 配置文件
│── alembic/
│ ├── versions/ # 数据库迁移文件
│ ├── env.py
│ ├── script.py.mako
│── alembic.ini
具体代码就展示一下 main.py
from fastapi import FastAPI
from core.config import settings
from core.middlewares import setup_middlewares
from routers import home, users
from core.event import lifespan
app = FastAPI(title=settings.PROJECT_NAME, version=settings.VERSION, lifespan=lifespan)
# 注册中间件
setup_middlewares(app)
# 注册路由
app.include_router(home.router)
app.include_router(users.router)
fastapi官方有个项目模板,搭建基础框架的时候可以参考 full-stack-fastapi-template。
其他的都不是问题,主要还是数据库连接,搭建框架的时候突然发现一个新的ORM库 SQLModel
,我还以为有能够与 Django 竞争的库。
没想到 底层还是使用了 SQLAlchemy
。SQLModel
也是 fastapi
作者搞的,基本就是在 SQLAlchemy
上适配了 Pydantic
。
然后数据库迁移还得用 alembic
。试着写了一下业务,这个库封装的不完全,还得暴露出 SQLAlchemy
,不太满意。网上查了一下,大家对其的评价也不高。
在搭建项目的过程中,还发现了其他新起的ORM框架,如 tortoise-orm
。同时也让我发现了 django-ninja
。
使用 django-ninja 搭建
项目结构就完全就是 django 的,可以自己在已有的 django 项目中直接引入。这是我的大致项目结构:
ninja_app/
├── manage.py # django入口文件
├── api/ # django-ninja API的目录
│ ├── __init__.py
│ ├── auth
│ │ ├── __init__.py
│ │ ├── schemas.py
│ │ └── views.py
├── app/ # django app 的目录
│ ├── __init__.py
│ └── account/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations/
│ │ ├── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── ninja_app/
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── utils/
├── __init__.py
├── middleware.py # 自定义中间件
└── security.py # 自定义认证类
Router(路由拆分)
django-ninja 借鉴了 fastapi,所以写法上和 fastapi 还有flask很像。
api/__init__.py
from ninja import NinjaAPI
from utils.security import TokenAuth, ApiKeyAuth
api_v1 = NinjaAPI(title="Ninja API", version='1.0', auth=[TokenAuth(), ApiKeyAuth()])
# api_v2 = NinjaAPI(version='2.0')
api_v1.add_router("/auth/", "api.auth.router_v1")
django-ninja 可以有多个 NinjaAPI 实例,所以很方便提供多版本API
api/auth/__init__.py
from ninja import Router
router_v1 = Router(tags=["Auth"])
from .views import *
ninja_app/urls.py
...
from api import api_v1
...
urlpatterns = [
...
path("api/v1/", api_v1.urls),
...
]
...
自定义API认证
我这里提供了两种认证,一种面向登录用户的(Token认证), 一种面向程序调用的方便集成(APIKey认证)
from ninja.security import APIKeyHeader, HttpBearer
class TokenAuth(HttpBearer):
def authenticate(self, request, token):
if key != 'token': # 自定义认证逻辑,认证不通过返回None即可返回403
return None
return token
class ApiKeyAuth(APIKeyHeader):
param_name: str = "X-API-Key"
def authenticate(self, request, key):
if key != 'xxxxx': # 自定义认证逻辑,认证不通过返回None即可返回403
return None
return key
API View和参数校验
以登录接口为例
api/auth/views.py
from api.auth import router_v1
from api.auth.schemas import LoginSchema
@router_v1.post("/login/", auth=None)
def login(request, payload: LoginSchema):
token = '123'
return {"token": token}
NinjaAPI 实例添加了认证,但是下面的某个API不需要认证,可以在装饰器传入参数
auth=None
api/auth/schemas.py
from typing_extensions import Self
from pydantic import model_validator
from ninja import Schema, Field
class LoginSchema(Schema):
username: str = Field(min_length=1, max_length=150)
password: str = Field(min_length=1, max_length=150)
@model_validator(mode='after')
def check_login(self) -> Self:
if self.username != 'xxx' or self.password != 'xxx': # 自定义登录验证
raise ValueError("Invalid username or password")
return self
django-ninja 的 Schema 使用的也是
Pydantic
,字段校验可以使用Field
, 也可以使用Pydantic - validators
结束语
使用 django-ninja 包装完的 django 项目,同样可以得倒一个支持 Async
OpenAPI
Pydantic
的现代 Web 后端。
并且你还可以使用 Django 的所有便利(ORM,Admin等)。
在选择 Web 框架时,大多数业务应用其实并不需要追求极致的性能。但在实际应用中,很多时候性能瓶颈并不在 Web 框架,而是在数据库操作上。数据库查询的优化和设计,通常是影响应用性能的关键因素。对于大多数企业级应用来说,框架的易用性、生态系统和团队的熟悉度往往是更重要的考量因素。Django-Ninja 不仅能够满足现代 Web 开发对高效、标准化、类型安全的要求,同时还能充分发挥 Django 丰富的生态和成熟的功能。
总的来说,无论是选择 FastAPI 还是 Django-Ninja,都取决于项目的具体需求和团队的技术栈。性能固然重要,但更重要的是在实际开发中能够提供稳定、可维护和可扩展的解决方案。
参考链接
- https://fastapi.tiangolo.com/learn/
- https://django-ninja.dev/
- https://docs.pydantic.dev/latest/concepts/validators/