FastAPI与Tortoise-ORM集成全攻略

FastAPI集成Tortoise-ORM实践

引言

在Python生态中,FastAPI凭借其高性能、易用性和现代特性(如类型注解、异步支持)迅速成为构建API服务的热门选择。而Tortoise-ORM作为一款专为异步框架设计的ORM工具,完美契合FastAPI的异步特性,提供了直观的数据库操作接口。本文将深入探讨如何在FastAPI项目中集成Tortoise-ORM,从基础配置到高级用法,为开发者提供一套完整的实践指南。

环境准备与基础配置

安装依赖

首先,确保你的开发环境已安装Python 3.7+。接着,通过pip安装FastAPI、Uvicorn(ASGI服务器)和Tortoise-ORM:

  1. pip install fastapi uvicorn tortoise-orm

项目结构规划

一个良好的项目结构有助于代码管理和维护。推荐采用以下结构:

  1. project/
  2. ├── app/
  3. ├── __init__.py
  4. ├── main.py # FastAPI应用入口
  5. ├── models/ # 数据库模型定义
  6. ├── __init__.py
  7. └── user.py # 用户模型示例
  8. ├── schemas/ # Pydantic模型,用于请求/响应验证
  9. ├── __init__.py
  10. └── user.py # 用户Schema示例
  11. ├── crud/ # 数据库操作逻辑
  12. ├── __init__.py
  13. └── user.py # 用户CRUD操作
  14. └── config.py # 配置文件,如数据库连接
  15. └── requirements.txt

配置Tortoise-ORM

config.py中定义数据库连接配置:

  1. from tortoise.contrib.fastapi import register_tortoise
  2. DB_CONFIG = {
  3. "connections": {
  4. "default": {
  5. "engine": "tortoise.backends.asyncpg",
  6. "credentials": {
  7. "host": "localhost",
  8. "port": "5432",
  9. "user": "postgres",
  10. "password": "yourpassword",
  11. "database": "mydatabase",
  12. },
  13. },
  14. },
  15. "apps": {
  16. "models": {
  17. "models": ["app.models"],
  18. "default_connection": "default",
  19. },
  20. },
  21. "use_tz": True,
  22. "timezone": "UTC",
  23. }

模型定义与数据库迁移

定义模型

app/models/user.py中定义用户模型:

  1. from tortoise import fields, models
  2. class User(models.Model):
  3. id = fields.IntField(pk=True)
  4. username = fields.CharField(max_length=50, unique=True)
  5. email = fields.CharField(max_length=255, unique=True)
  6. is_active = fields.BooleanField(default=True)
  7. created_at = fields.DatetimeField(auto_now_add=True)
  8. def __str__(self):
  9. return self.username

数据库迁移

Tortoise-ORM不直接提供迁移工具,但可以结合Aerich(专为Tortoise设计的迁移工具)使用。首先安装Aerich:

  1. pip install aerich

初始化Aerich配置(通常在项目根目录创建aerich.iniaerich目录):

  1. [aerich]
  2. tortoise_orm = app.config.DB_CONFIG
  3. location = ./migrations

初始化数据库并生成迁移:

  1. aerich init -t app.config.DB_CONFIG
  2. aerich init-db
  3. # 修改模型后
  4. aerich migrate
  5. aerich upgrade

FastAPI应用集成

注册Tortoise-ORM

app/main.py中注册Tortoise-ORM到FastAPI应用:

  1. from fastapi import FastAPI
  2. from app.config import DB_CONFIG
  3. from tortoise.contrib.fastapi import register_tortoise
  4. app = FastAPI()
  5. register_tortoise(
  6. app,
  7. config=DB_CONFIG,
  8. generate_schemas=True, # 自动生成数据库表结构
  9. add_exception_handlers=True,
  10. )

创建CRUD操作

app/crud/user.py中实现用户CRUD操作:

  1. from app.models import User
  2. from typing import Optional
  3. async def create_user(username: str, email: str) -> User:
  4. user = User(username=username, email=email)
  5. await user.save()
  6. return user
  7. async def get_user_by_id(user_id: int) -> Optional[User]:
  8. return await User.get_or_none(id=user_id)
  9. async def get_users() -> list[User]:
  10. return await User.all().offset(0).limit(100)
  11. async def update_user(user_id: int, **kwargs) -> Optional[User]:
  12. await User.filter(id=user_id).update(**kwargs)
  13. return await get_user_by_id(user_id)
  14. async def delete_user(user_id: int) -> bool:
  15. affected = await User.filter(id=user_id).delete()
  16. return affected > 0

定义API路由

app/main.py或单独的路由文件中定义API端点:

  1. from fastapi import APIRouter, HTTPException
  2. from app.crud.user import create_user, get_user_by_id, get_users, update_user, delete_user
  3. from app.schemas.user import UserCreate, UserUpdate, User
  4. router = APIRouter()
  5. @router.post("/users/", response_model=User)
  6. async def create_user_endpoint(user_in: UserCreate):
  7. user = await create_user(username=user_in.username, email=user_in.email)
  8. return user
  9. @router.get("/users/{user_id}", response_model=User)
  10. async def read_user_endpoint(user_id: int):
  11. user = await get_user_by_id(user_id)
  12. if user is None:
  13. raise HTTPException(status_code=404, detail="User not found")
  14. return user
  15. # 其他端点...

高级特性与最佳实践

事务处理

Tortoise-ORM支持事务,确保数据一致性:

  1. from tortoise import transactions
  2. async def transfer_funds(from_id: int, to_id: int, amount: float):
  3. async with transactions.in_transaction() as conn:
  4. # 假设有Account模型
  5. from_account = await Account.get(id=from_id).using_db(conn)
  6. to_account = await Account.get(id=to_id).using_db(conn)
  7. if from_account.balance < amount:
  8. raise ValueError("Insufficient funds")
  9. from_account.balance -= amount
  10. to_account.balance += amount
  11. await from_account.save(using_db=conn)
  12. await to_account.save(using_db=conn)

性能优化

  • 批量操作:使用bulk_createbulk_update提高批量操作效率。
  • 索引优化:在频繁查询的字段上添加索引。
  • 连接池配置:根据应用负载调整数据库连接池大小。

测试策略

  • 单元测试:使用pytesttortoise-orm.test模块进行模型测试。
  • 集成测试:使用TestClient模拟API请求,验证端到端功能。
  • 数据库隔离:测试时使用独立数据库或事务回滚,避免数据污染。

结论

FastAPI与Tortoise-ORM的集成,为开发者提供了一个高效、灵活且易于维护的API开发解决方案。通过本文的实践指南,你不仅能够快速上手基础配置和CRUD操作,还能深入理解事务处理、性能优化等高级特性。随着项目的不断演进,持续探索和优化集成方案,将助力你构建出更加健壮、高效的Web应用。