跳转到内容

FastAPI + Django 双框架架构

FastAPI + Django 双框架架构

学习目标

理解 Khoj 如何将 FastAPI 和 Django 两个框架融合在一个应用中,各自的职责边界,以及中间件管道的组织方式。

项目实践

职责分工

Khoj 选择同时使用两个框架,各自扬长:

框架职责原因
FastAPIAPI 路由、WebSocket、流式响应原生 async/await、现代 Python 类型注解、StreamingResponse
DjangoORM、数据模型、Migration、Admin、认证成熟的 ORM + Migration 系统、Admin 面板、认证后端生态

启动流程

main.py 中的 run() 函数(约 200 行)是启动入口:

1. 解析 CLI 参数(host, port, anonymous-mode 等)
2. 配置 Django settings
3. 运行 Django migration:call_command("migrate")
4. 收集静态文件:collectstatic
5. 执行初始化逻辑:initialization()
6. 启动 APScheduler 调度器
7. 配置 FastAPI 路由
8. 挂载 Django 为子应用:app.mount("/server", django_asgi_app)
9. 配置中间件(auth → session → CORS → HTTPS redirect)
10. 启动 uvicorn

Django 子应用挂载

from django.conf import settings
from django.core.wsgi import get_wsgi_application
from fastapi import FastAPI
# 创建 FastAPI 应用
app = FastAPI()
# 挂载 Django 为子应用
django_asgi_app = get_asgi_application()
app.mount("/server", django_asgi_app)

FastAPI 的 mount() 将 Django 的 ASGI 应用挂载到 /server 路径前缀下。所有 /server/* 的请求直接交给 Django 处理,其余路径由 FastAPI 路由处理。

中间件执行顺序

中间件的顺序至关重要:

# 1. 认证中间件 - 最先执行,建立用户上下文
app.add_middleware(UserAuthenticationBackend)
# 2. Session 中间件 - 在认证之后,用于存储 session 数据
app.add_middleware(SessionMiddleware)
# 3. CORS 中间件 - 在业务逻辑之前,处理跨域预检
app.add_middleware(CORSMiddleware, ...)
# 4. HTTPS 重定向 - 最后,确保前面所有中间件都在 HTTPS 下运行
# (通过 middleware 配置)

为什么认证在 Session 之前? 因为认证中间件需要检查请求头中的 bearer token 或 session cookie 来确定用户身份,Session 中间件依赖认证结果来决定如何加载 session 数据。

共享数据库连接

FastAPI 和 Django 共享同一个 PostgreSQL 连接池。关键点是:

  • Django ORM 是同步的,在 FastAPI 的 async 环境中需要通过 sync_to_async 包装
  • Khoj 的数据库适配器(src/khoj/database/adapters/)提供了 async 版本的 CRUD 操作
  • ProcessLock 模型用于确保索引操作等独占任务的线程安全

问题与规避

问题影响规避策略
同步 ORM 阻塞 async 事件循环响应延迟使用 sync_to_async 包装数据库操作;或提供原生 async 适配器
中间件顺序错误认证绕过或 CORS 失败严格按照 auth → session → CORS → HTTPS 顺序注册
启动时自动 migration 失败应用无法启动生产环境可通过环境变量禁用自动 migration
双框架的配置分散维护困难src/khoj/app/settings.py 统一管理 Django settings,CLI 参数覆盖关键配置

设计取舍

为什么不用纯 FastAPI + SQLAlchemy?

Django 的 ORM + Migration + Admin 是成熟且经过大量项目验证的组合。如果切换到 SQLAlchemy,需要自行实现 Migration 系统(如 Alembic)、管理面板、认证后端等。对于 Khoj 这种需要快速迭代的项目,Django 的”电池内置”哲学节省了开发时间。

为什么不用纯 Django?

Django 的 async 支持和 WebSocket 支持相对滞后。Khoj 的流式聊天响应和 WebSocket 实时通信在现代 FastAPI 中是原生能力,在 Django 中需要额外的配置和 workaround。

参考来源