FastAPI 集成 Tortoise-ORM 实践
引言
在构建现代 Web 应用时,API 的开发效率与数据持久化能力是关键。FastAPI 凭借其高性能和异步支持成为 Python 生态中的热门选择,而 Tortoise-ORM 作为一款异步 ORM 工具,能够无缝适配 FastAPI 的异步特性。本文将详细介绍如何在 FastAPI 项目中集成 Tortoise-ORM,从基础配置到高级功能,帮助开发者快速上手并优化实践。
一、环境准备与安装
1. 创建 FastAPI 项目
首先,确保已安装 Python 3.8+ 环境,并使用以下命令创建 FastAPI 项目:
mkdir fastapi_tortoise_demo && cd fastapi_tortoise_demopython -m venv venvsource venv/bin/activate # Linux/macOS# 或 venv\Scripts\activate (Windows)pip install fastapi uvicorn
2. 安装 Tortoise-ORM
Tortoise-ORM 支持异步操作,需额外安装:
pip install tortoise-orm[asyncpg] # 推荐使用 asyncpg 作为 PostgreSQL 驱动
若使用 MySQL,可替换为 tortoise-orm[aiomysql]。
3. 配置数据库连接
在项目根目录创建 config.py,定义数据库连接参数:
from pydantic import BaseSettingsclass Settings(BaseSettings):DATABASE_URL: str = "postgres://user:password@localhost:5432/mydb"class Config:env_file = ".env"settings = Settings()
通过环境变量管理敏感信息,避免硬编码。
二、Tortoise-ORM 集成 FastAPI
1. 初始化 Tortoise-ORM
在 main.py 中初始化 Tortoise,并挂载到 FastAPI 应用:
from fastapi import FastAPIfrom tortoise.contrib.fastapi import register_tortoisefrom config import settingsapp = FastAPI()register_tortoise(app,db_url=settings.DATABASE_URL,modules={"models": ["app.models"]}, # 指定模型所在模块generate_schemas=True, # 自动生成数据库表add_exception_handlers=True, # 添加 ORM 异常处理)
2. 定义数据模型
在 app/models.py 中定义模型,继承自 tortoise.models.Model:
from tortoise import fields, modelsclass User(models.Model):id = fields.IntField(pk=True)username = fields.CharField(max_length=50, unique=True)email = fields.CharField(max_length=255, unique=True)is_active = fields.BooleanField(default=True)created_at = fields.DatetimeField(auto_now_add=True)class PydanticMeta:computed = ["created_at"] # 避免序列化时返回自动字段def __str__(self):return self.username
通过 PydanticMeta 控制序列化行为,避免泄露敏感字段。
三、CRUD 操作实现
1. 创建记录
使用 User.create() 方法异步创建用户:
from fastapi import APIRouterfrom app.models import Userrouter = APIRouter()@router.post("/users/")async def create_user(username: str, email: str):user = await User.create(username=username, email=email)return {"id": user.id, "username": user.username}
2. 查询记录
-
查询单个用户:
@router.get("/users/{user_id}/")async def get_user(user_id: int):user = await User.get(id=user_id)if not user:raise HTTPException(status_code=404, detail="User not found")return user
-
查询所有用户:
@router.get("/users/")async def list_users():return await User.all().values("id", "username", "email")
3. 更新与删除
-
更新用户:
@router.patch("/users/{user_id}/")async def update_user(user_id: int, username: str = None, email: str = None):await User.filter(id=user_id).update(username=username, email=email)return {"message": "User updated"}
-
删除用户:
@router.delete("/users/{user_id}/")async def delete_user(user_id: int):await User.filter(id=user_id).delete()return {"message": "User deleted"}
四、高级功能实践
1. 事务管理
使用 Tortoise.transaction() 确保数据一致性:
from tortoise import transactions@router.post("/transfer/")async def transfer_funds(from_id: int, to_id: int, amount: float):async with transactions.in_transaction() as conn:from_user = await User.get(id=from_id).using_db(conn)to_user = await User.get(id=to_id).using_db(conn)if from_user.balance < amount:raise HTTPException(status_code=400, detail="Insufficient funds")from_user.balance -= amountto_user.balance += amountawait from_user.save(using_db=conn)await to_user.save(using_db=conn)return {"message": "Transfer successful"}
2. 复杂查询
-
分页查询:
@router.get("/users/page/{page}/")async def paginate_users(page: int = 1, page_size: int = 10):skip = (page - 1) * page_sizeusers = await User.all().offset(skip).limit(page_size)total = await User.all().count()return {"data": users, "total": total}
-
关联查询:
假设存在Order模型与User一对多关联:class Order(models.Model):user = fields.ForeignKeyField("models.User", related_name="orders")amount = fields.FloatField()# ...@router.get("/users/{user_id}/orders/")async def get_user_orders(user_id: int):orders = await User.get(id=user_id).prefetch_related("orders")return orders.orders
五、性能优化建议
-
连接池配置:
在数据库 URL 中添加连接池参数,例如:postgres://user:password@localhost:5432/mydb?max_connections=20
-
选择性加载字段:
查询时仅加载必要字段,减少数据传输:await User.all().values("id", "username")
-
索引优化:
在频繁查询的字段上添加索引:class User(models.Model):email = fields.CharField(max_length=255, unique=True, index=True)
-
批量操作:
使用bulk_create批量插入数据:users = [User(username=f"user{i}", email=f"user{i}@example.com") for i in range(100)]await User.bulk_create(users, batch_size=50)
六、常见问题与解决方案
-
模型未同步:
确保generate_schemas=True,并检查数据库权限。 -
异步锁冲突:
避免在事务中执行耗时操作,如外部 API 调用。 -
N+1 查询问题:
使用prefetch_related预加载关联数据。
总结
通过本文的实践指南,开发者可以高效地在 FastAPI 中集成 Tortoise-ORM,实现类型安全的数据库操作。从基础配置到高级事务管理,Tortoise-ORM 的异步特性与 FastAPI 完美契合,为构建高性能 Web API 提供了强大支持。建议结合实际项目需求,进一步探索 Tortoise-ORM 的插件生态(如 tortoise-migrations 数据库迁移工具),持续提升开发效率。