title: Tortoise-ORM与FastAPI集成:异步模型定义与实践

date: 2025/04/20 11:38:23

updated: 2025/04/20 11:38:23

author: cmdragon

excerpt:

Tortoise-ORM通过类继承方式定义数据模型,每个模型类对应数据库中的一张表。模型字段类型与数据库类型自动映射,支持主键、唯一约束、索引等配置。模型间通过外键建立关联,支持异步查询和CRUD操作。FastAPI集成时,通过register_tortoise初始化数据库连接,并结合Pydantic模型实现数据验证。常见错误包括字段验证失败和数据库连接超时,可通过中间件和连接池配置解决。

categories:

  • 后端开发
  • FastAPI

tags:

  • Tortoise-ORM
  • FastAPI
  • 异步数据库
  • 模型定义
  • 数据库配置
  • CRUD接口
  • 错误处理


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

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

第一章 Tortoise-ORM异步模型定义基础

1.1 模型类创建方法

在FastAPI项目中,数据模型是连接业务逻辑与数据库的核心枢纽。Tortoise-ORM采用类继承方式定义模型,每个模型类对应数据库中的一张表。以下是用户模型的完整示例:

from tortoise.models import Model
from tortoise import fields class User(Model):
id = fields.IntField(pk=True) # 主键字段,自动递增
username = fields.CharField(max_length=50, unique=True) # 唯一用户名
email = fields.CharField(max_length=100, index=True) # 带索引的邮箱字段
created_at = fields.DatetimeField(auto_now_add=True) # 自动记录创建时间
is_active = fields.BooleanField(default=True) # 账户激活状态
credit = fields.DecimalField(max_digits=10, decimal_places=2, default=0.0) # 精确数值存储 class Meta:
table = "auth_users" # 自定义表名
ordering = ["-created_at"] # 默认排序规则

该模型在数据库中会生成如下结构的表(以PostgreSQL为例):

CREATE TABLE auth_users
(
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP NOT NULL,
is_active BOOLEAN NOT NULL,
credit NUMERIC(10, 2) NOT NULL
);

1.2 字段类型映射原理

Tortoise-ORM的字段系统实现了Python类型与数据库类型的智能转换。当我们执行数据库迁移时,ORM会自动根据模型字段类型生成对应的DDL语句:

Python字段类型 PostgreSQL类型 MySQL类型 SQLite类型
CharField VARCHAR VARCHAR TEXT
UUIDField UUID CHAR(36) TEXT
DatetimeField TIMESTAMP DATETIME(6) TEXT
JSONField JSONB JSON TEXT
FloatField DOUBLE PRECISION DOUBLE REAL

特殊的字段参数:

  • auto_now_add=True:仅在对象创建时记录时间
  • auto_now=True:每次保存对象时更新时间
  • description='字段说明':生成数据库注释
  • db_index=True:创建独立索引(比index参数更灵活)

1.3 模型关联配置

关联关系配置是ORM的核心功能之一。我们通过外键字段建立模型间的关联:

class Author(Model):
name = fields.CharField(max_length=100) class Book(Model):
title = fields.CharField(max_length=200)
author = fields.ForeignKeyField(
'models.Author',
related_name='books',
on_delete=fields.CASCADE
)
published_date = fields.DateField()

关联查询示例:

# 获取作者及其所有书籍
author = await Author.filter(name="J.K. Rowling").prefetch_related('books') # 创建关联对象
await Book.create(
title="Harry Potter and the Philosopher's Stone",
author=author,
published_date=date(1997, 6, 26)
)

第二章 FastAPI集成实践

2.1 数据库配置

在FastAPI启动配置中初始化数据库连接:

from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise app = FastAPI() DB_CONFIG = {
"connections": {
"default": "postgres://user:password@localhost:5432/mydb"
},
"apps": {
"models": {
"models": ["models"],
"default_connection": "default",
}
},
"use_tz": True, # 启用时区支持
"timezone": "Asia/Shanghai"
} register_tortoise(
app,
config=DB_CONFIG,
generate_schemas=True, # 自动生成表结构
add_exception_handlers=True # 启用ORM异常处理
)

2.2 路由与模型结合

创建完整的CRUD接口示例:

from pydantic import BaseModel
from fastapi import APIRouter router = APIRouter() class UserCreate(BaseModel):
username: str
email: str @router.post("/users")
async def create_user(user: UserCreate):
db_user = await User.create(**user.dict())
return {
"id": db_user.id,
"created_at": db_user.created_at.isoformat()
} @router.get("/users/{user_id}")
async def get_user(user_id: int):
user = await User.get_or_none(id=user_id).values(
"username", "email", "created_at")
return user or {"error": "User not found"}

第三章 课后Quiz

问题1:如何设置UUID主键?

A) id = fields.UUIDField()

B) id = fields.UUIDField(pk=True)

C) id = fields.UUIDField(primary_key=True)

正确答案:C

解析:在Tortoise-ORM中,设置主键需要显式指定primary_key参数。虽然pk是常用的快捷参数,但UUIDField必须使用完整的primary_key=True才能正确生成主键约束。

问题2:异步查询的优势包括?

A) 减少内存占用

B) 避免阻塞事件循环

C) 提高CPU利用率

正确答案:B

解析:异步查询允许事件循环在等待数据库响应时处理其他任务,特别适合高并发的I/O密集型场景。内存占用和CPU利用率主要与程序实现方式相关,并非异步的直接优势。

第四章 常见报错解决方案

4.1 字段验证失败(422错误)

错误示例:

{
"detail": [
{
"loc": [
"body",
"username"
],
"msg": "ensure this value has at most 50 characters",
"type": "value_error.any_str.max_length"
}
]
}

解决方法:

  1. 检查请求数据是否符合模型约束
  2. 在Pydantic模型中设置相同的验证规则
  3. 使用中间件捕获验证异常:
from fastapi.exceptions import RequestValidationError

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return JSONResponse(
status_code=400,
content={"detail": exc.errors()},
)

4.2 数据库连接超时

错误信息:

DBConnectionError: Can't connect to MySQL server on 'localhost'

排查步骤:

  1. 验证数据库服务是否正常运行
  2. 检查连接字符串格式:dialect://user:password@host:port/dbname
  3. 增加连接池配置:
DB_CONFIG = {
"connections": {
"default": {
"engine": "tortoise.backends.asyncpg",
"credentials": {
"host": "localhost",
"port": "5432",
"database": "mydb",
"user": "user",
"password": "password",
"minsize": 3, # 最小连接数
"maxsize": 20 # 最大连接数
}
}
}
}

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:

Tortoise-ORM与FastAPI集成:异步模型定义与实践 | cmdragon's Blog

往期文章归档:

Tortoise-ORM与FastAPI集成:异步模型定义与实践的更多相关文章

  1. JavaScript 学习笔记之线程异步模型

    核心的javascript程序语言并没有包含任何的线程机制,客户端javascript程序也没有任何关于线程的定义,事件驱动模式下的javascript语言并不能实现同时执行,即不能同时执行两个及以上 ...

  2. beego——模型定义

    复杂的模型定义不是必须的,此功能用作数据库数据转换和自动建表 默认的表名规则,使用驼峰转蛇形: AuthUser -> auth_user Auth_User -> auth__user ...

  3. Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别

    Task C# 多线程和异步模型 TPL模型   Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...

  4. ​结合异步模型,再次总结Netty多线程编码最佳实践

    更多技术分享可关注我 前言 本文重点总结Netty多线程的一些编码最佳实践和注意事项,并且顺便对Netty的线程调度模型,和异步模型做了一个汇总.原文:​​结合异步模型,再次总结Netty多线程编码最 ...

  5. 【重磅】iNeuOS工业互联平台,系统集成业务模型和WEB组态视图建模集成3D模型

    目       录 1.      概述... 1 2.      平台演示... 2 3.      系统集成业务模型... 2 4.      WEB组态视图建模集成3D模型... 3 5.    ...

  6. 以两种异步模型应用案例,深度解析Future接口

    摘要:本文以实际案例的形式分析了两种异步模型,并从源码角度深度解析Future接口和FutureTask类. 本文分享自华为云社区<[精通高并发系列]两种异步模型与深度解析Future接口(一) ...

  7. 【高并发】两种异步模型与深度解析Future接口

    大家好,我是冰河~~ 本文有点长,但是满满的干货,以实际案例的形式分析了两种异步模型,并从源码角度深度解析Future接口和FutureTask类,希望大家踏下心来,打开你的IDE,跟着文章看源码,相 ...

  8. .NET - 基于事件的异步模型

    注:这是大概四年前写的文章了.而且我离开.net领域也有四年多了.本来不想再发表,但是这实际上是Active Object模式在.net中的一种重要实现方法,因此我把它掏出来发布一下.如果该模型有新的 ...

  9. Entity Framework 6 Recipes 2nd Edition(11-1)译 -> 从“模型定义”函数返回一个标量值

    第11章函数 函数提供了一个有力代码复用机制, 并且让你的代码保持简洁和易懂. 它们同样也是EF运行时能利用的数据库层代码.函数有几类: Rowset Functions, 聚合函数, Ranking ...

  10. Entity Framework 6 Recipes 2nd Edition(11-2)译 -> 用”模型定义”函数过滤实体集

    11-2. 用”模型定义”函数过滤实体集 问题 想要创建一个”模型定义”函数来过滤一个实体集 解决方案 假设我们已有一个客户(Customer)和票据Invoice)模型,如Figure 11-2所示 ...

随机推荐

  1. Maven配置代理

    Maven配置代理 找到settings.xml文件: 通常位于Maven安装目录下的conf文件夹中.或者位于用户目录下的.m2文件夹中(例如:$HOME/.m2/settings.xml). 编辑 ...

  2. linux系统ntp时间同步

    linux系统ntp时间同步 概要 linux系统时间同步有ntp和chrony两种不同实现方式. 两者相比chrony性能更优,如果系统支持,那么能够使用chrony尽量使用它. chrony 具有 ...

  3. Iceberg的Copy on Write和Merge On Read介绍

    一.默认的Copy on Write Copy no Write模式指的是在进行更新数据时,先将数据拷贝出来进行相应的更新,再替换掉原先的数据 二.Merge On Read读取时合并 在v2版本才支 ...

  4. vmware workstation 17 pro激活密钥

    vmware workstation 17 pro激活密钥,通用批量永久激活许可 17:JU090-6039P-08409-8J0QH-2YR7F 16:ZF3R0-FHED2-M80TY-8QYGC ...

  5. 全程使用 AI 从 0 到 1 写了个小工具

    背景 好长时间没写技术方面的文章了,主要的原因是AI的发展实在太快太快,尤其是从去年ChatGPT的普及到今年DeepSeek的爆火,AI的世界可谓是三天一个小变化五天一个大版本,AI的能力每天都在以 ...

  6. 不止排名,Google SEO 10 大核心心得分享

    原博客:https://bysocket.com/seo-tips-2025/ 在过去的一年中,我深入实践了 Google SEO,积累了自己一些经验和看法.以下是我的实操心得,希望对大家有所帮助. ...

  7. 【由技及道】量子构建交响曲:Jenkinsfile流水线的十一维编程艺术【人工智障AI2077的开发日志008】

    摘要:当代码提交触发时空涟漪,当构建流水线穿越量子维度--欢迎来到自动化构建的终极形态.本文将揭示如何用Jenkinsfile编写量子构建乐章,让每次代码提交都成为跨维度交响乐的音符. 动机:构建系统 ...

  8. 【Python】尝试切换py版本

    失败 问chatgpt,怎么把abaqus python 版本切换到py3.6,结果失败. chatgpt给出的建议: 修改abaqus_v6.env,明显扯淡!我就尝试在custom_v6.env中 ...

  9. HTTP 尝试获取 Client IP

    HTTP 中获取 Client IP 相关策略需求, 在当下网络环境中多数只能提供建议作用. 更多的是 通过其它唯一标识来挖掘更多潜在价值. 本文主要就一个内容, 如何最大可能尝试在 HTTP 请求中 ...

  10. PV、UV、VV、IP含义及计算方式

    什么是PV? PV 即 Page View,网站浏览量,指页面浏览的次数,用以衡量网站用户访问的网页数量. 用户每次打开一个页面便记录1次PV,多次打开同一页面则浏览量累计.一般来说,PV与来访者的数 ...