Tortoise-ORM FastAPI integration 快速入门


前言

初衷:在学习的时候发现 Tortoise-ORM FastAPI integration 官方文档缺中文版,翻阅英文文档效率低,萌生翻译想法。
本系列旨在原汁原味的翻译 Tortoise-ORM FastAPI integration 官方文档,帮助英语不好的小伙伴快速学习使用方法。
如果觉得翻译不错,欢迎在文章底部请博主喝杯奶茶,您的鼓励就是俺最大的动力!😄

快速上手

安装

  • 首先,你需要安装 Tortoise:
pip install tortoise-orm
  • 你也可以使用数据库驱动程序进行安装:
pip install tortoise-orm[asyncpg]
  • 或者 PsycoPG:
pip install tortoise-orm[psycopg]
  • 对于 MySQL:
pip install tortoise-orm[asyncmy]
  • 对于 Microsoft SQL Server/Oracle:
pip install tortoise-orm[asyncodbc]

除了 asyncpgpsycopg 之外,通过 aiosqliteasyncmy驱动程序,Tortoise-ORM 还支持 sqliteasyncmy。通过适合 asyncio 数据库驱动,您可以更轻松地实现后端。

可选加速器

以下库可用作加速器:

  • orjson:如果安装了 JSON SerDes,默认自动使用。
  • uvloop:已经证明可以提升性能,但需要进行一定设置。请查看 uvloop 文档获取更多信息。如果您已经使用了一种框架,它可能已经在使用了。
  • ciso8601:自动使用(如果已安装)。由于 Windows 上缺少 C 编译器,因此不会自动安装。在 Linux/CPython 上默认已安装。

您可以安装上述所有加速器:

pip install tortoise-orm[accel]

教程

tortoise 的主实体是 tortoise.models.Model。您可以开始编写如下模型:

from tortoise.models import Model
from tortoise import fields

class Tournament(Model):
    # Defining `id` field is optional, it will be defined automatically
    # if you haven't done it yourself
    id = fields.IntField(primary_key=True)
    name = fields.CharField(max_length=255)

    # Defining ``__str__`` is also optional, but gives you pretty
    # represent of model in debugger and interpreter
    def __str__(self):
        return self.name


class Event(Model):
    id = fields.IntField(primary_key=True)
    name = fields.CharField(max_length=255)
    # References to other models are defined in format
    # "{app_name}.{model_name}" - where {app_name} is defined in tortoise config
    tournament = fields.ForeignKeyField('models.Tournament', related_name='events')
    participants = fields.ManyToManyField('models.Team', related_name='events', through='event_team')

    def __str__(self):
        return self.name


class Team(Model):
    id = fields.IntField(primary_key=True)
    name = fields.CharField(max_length=255)

    def __str__(self):
        return self.name

在关系数据库中,主实体(primary entity)是关系模型中的一个重要概念,它指的是在多个实体之间建立关系时,作为“主键”(primary key)的属性所在的实体。

Note: 您可以在 Models 中阅读更多有关定义模型的信息

在定义所有模型后,Tortoise 需要您初始化它们,以便在模型之间创建逆向关系,明确您的数据库客户端与适当的模型匹配的关系。

你可以尝试这样做:

from tortoise import Tortoise

async def init():
    # Here we create a SQLite DB using file "db.sqlite3"
    #  also specify the app name of "models"
    #  which contain models from "app.models"
    await Tortoise.init(
        db_url='sqlite://db.sqlite3',
        modules={'models': ['app.models']}
    )
    # Generate the schema
    await Tortoise.generate_schemas()

在这里,我们使用默认的 aiosqlite 客户端创建与 SQLite DB 数据库的连接,然后发现并初始化模型。

generate_schema 在空数据库上生成 schema,你不应该在每个应用程序初始化时运行它,只需要在您的主代码之外运行一次。

如果在一个简单的脚本中运行,您可以这样做:

run_async(init())

run_async 是一个辅助函数,用于运行简单的异步 Tortoise 脚本。如果您在服务中运行 Tortoise ORM,请查看 The Importance of cleaning up

在那之后,您就可以开始使用您的模型了:

# Create instance by save
tournament = Tournament(name='New Tournament')
await tournament.save()

# Or by .create()
await Event.create(name='Without participants', tournament=tournament)
event = await Event.create(name='Test', tournament=tournament)
participants = []
for i in range(2):
    team = await Team.create(name='Team {}'.format(i + 1))
    participants.append(team)

# M2M Relationship management is quite straightforward
# (look for methods .remove(...) and .clear())
await event.participants.add(*participants)

# You can query related entity just with async for
async for team in event.participants:
    pass

# After making related query you can iterate with regular for,
# which can be extremely convenient for using with other packages,
# for example some kind of serializers with nested support
for team in event.participants:
    pass


# Or you can make preemptive call to fetch related objects,
# so you can work with related objects immediately
selected_events = await Event.filter(
    participants=participants[0].id
).prefetch_related('participants', 'tournament')
for event in selected_events:
    print(event.tournament.name)
    print([t.name for t in event.participants])

# Tortoise ORM supports variable depth of prefetching related entities
# This will fetch all events for team and in those team tournament will be prefetched
await Team.all().prefetch_related('events__tournament')

# You can filter and order by related models too
await Tournament.filter(
    events__name__in=['Test', 'Prod']
).order_by('-events__participants__name').distinct()