FastAPI与Tortoise-ORM实现关系型数据库关联


title: FastAPI与Tortoise-ORM实现关系型数据库关联

date: 2025/04/21 10:51:41

updated: 2025/04/21 10:51:41

author: cmdragon

excerpt:

FastAPI与Tortoise-ORM结合实现关系型数据库关联,支持1:1、1:N和M:N关系。1:N关系通过ForeignKeyField定义,M:N关系使用ManyToManyField处理。Pydantic模型用于数据验证和序列化,路由实现中通过prefetch_related优化查询性能。M:N关系通过中间表操作,支持复杂查询。常见报错包括422验证错误和外键约束失败,可通过事务和类型检查解决。安装依赖后,使用uvicorn启动服务进行测试。

categories:

  • 后端开发
  • FastAPI

tags:

  • FastAPI
  • Tortoise-ORM
  • 关系型数据库
  • 1:N关系
  • M:N关系
  • 异步数据库操作
  • 数据库关联实现

扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意

一、FastAPI与Tortoise-ORM关系型数据库关联实现

1. 关系型数据库关联基础

在关系型数据库中,表与表之间的关联主要分为三种类型:

  • 1:1关系(如用户与身份证)
  • 1:N关系(如作者与书籍)
  • M:N关系(如学生与课程)

FastAPI通过Tortoise-ORM实现异步数据库操作时,使用ForeignKeyFieldManyToManyField

字段类型处理关联关系。相比同步ORM,异步实现需要特别注意await的使用和查询优化。

2. 1:N关系实现(作者与书籍案例)

2.1 模型定义

python 复制代码
# models.py
from tortoise.models import Model
from tortoise import fields


class Author(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)
    # 反向关系查询字段
    books = fields.ReverseRelation["Book"]


class Book(Model):
    id = fields.IntField(pk=True)
    title = fields.CharField(max_length=255)
    author = fields.ForeignKeyField(
        "models.Author",
        related_name="books",
        on_delete=fields.CASCADE
    )

2.2 Pydantic模型

python 复制代码
# schemas.py
from pydantic import BaseModel


class AuthorCreate(BaseModel):
    name: str


class BookCreate(BaseModel):
    title: str
    author_id: int


class AuthorOut(BaseModel):
    id: int
    name: str
    books: list[dict] = []

    class Config:
        orm_mode = True

2.3 路由实现

python 复制代码
# main.py
from fastapi import FastAPI, HTTPException
from models import Author, Book
from schemas import AuthorCreate, BookCreate, AuthorOut

app = FastAPI()


@app.post("/authors/", response_model=AuthorOut)
async def create_author(author: AuthorCreate):
    db_author = await Author.create(**author.dict())
    return await AuthorOut.from_tortoise_orm(db_author)


@app.get("/authors/{author_id}", response_model=AuthorOut)
async def get_author(author_id: int):
    author = await Author.get(id=author_id).prefetch_related("books")
    if not author:
        raise HTTPException(status_code=404, detail="Author not found")
    return await AuthorOut.from_tortoise_orm(author)

3. M:N关系实现(学生与课程案例)

3.1 模型定义

python 复制代码
# models.py
class Student(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)
    courses = fields.ManyToManyField(
        "models.Course",
        related_name="students",
        through="student_course"
    )


class Course(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)

3.2 中间表操作

python 复制代码
# 添加选课关系
student = await Student.get(id=1)
course = await Course.get(id=2)
await student.courses.add(course)

# 查询学生选课
student_with_courses = await Student.get(id=1).prefetch_related("courses")

3.3 复杂查询示例

python 复制代码
# 查询选修数学课的学生
math_students = await Student.filter(
    courses__name="Math"
).prefetch_related("courses")

4. 课后Quiz

Q1:当建立1:N关系时,为什么要使用prefetch_related()方法?

A. 提高查询性能

B. 避免循环引用

C. 处理分页请求

D. 验证数据格式

正确答案:A

解析:prefetch_related()用于预加载关联数据,通过单次数据库查询获取所有相关记录,避免N+1查询问题,显著提升查询效率。

Q2:M:N关系中,through参数的作用是什么?

A. 定义中间表名称

B. 指定关联字段类型

C. 设置级联删除规则

D. 声明索引字段

正确答案:A

解析:through参数用于自定义中间表名称,当需要向中间表添加额外字段时,可以显式创建中间模型。

5. 常见报错解决方案

报错1:422 Validation Error

json 复制代码
{
  "detail": [
    {
      "loc": [
        "body",
        "author_id"
      ],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ]
}

解决方法:

  1. 检查请求体数据格式是否符合JSON规范
  2. 确认字段类型与Pydantic模型定义一致
  3. 使用try/except捕获类型转换异常

报错2:IntegrityError外键约束失败

复制代码
sqlite3.IntegrityError: FOREIGN KEY constraint failed

解决方法:

  1. 检查关联ID是否存在
  2. 确认数据库事务完整性
  3. 使用atomic()包裹关联操作:
python 复制代码
async with in_transaction():
    author = await Author.create(name="J.K. Rowling")
    await Book.create(title="Harry Potter", author=author)

预防建议:

  1. 始终在数据库操作中使用事务
  2. 为关联字段添加索引
  3. 使用select_related和prefetch_related优化查询

运行准备

安装依赖:

bash 复制代码
pip install fastapi uvicorn tortoise-orm pydantic

启动服务:

bash 复制代码
uvicorn main:app --reload

通过以上实现,开发者可以完整掌握FastAPI中异步数据库关联操作的核心要点。建议在Postman中测试接口时,重点关注关联数据的完整性和查询效率表现。

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:FastAPI与Tortoise-ORM实现关系型数据库关联 | cmdragon's Blog

往期文章归档: