Tortoise-orm 使用(三) 一对一,一对多,多对多关系表及操作

发布时间:2024年01月19日

基于官方的示例模型

from tortoise import Tortoise, fields, run_async
from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator
from tortoise.models import Model


class Tournament(Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()
    created_at = fields.DatetimeField(auto_now_add=True)

    events: fields.ReverseRelation["Event"]

    class Meta:
        ordering = ["name"]


class Event(Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()
    created_at = fields.DatetimeField(auto_now_add=True)
    tournament: fields.ForeignKeyNullableRelation["Tournament"] = fields.ForeignKeyField(
        "models.Tournament", related_name="events", null=True
    )
    participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField(
        "models.Team", related_name="events", through="event_team"
    )
    address: fields.OneToOneNullableRelation["Address"]

    class Meta:
        ordering = ["name"]


class Address(Model):
    city = fields.CharField(max_length=64)
    street = fields.CharField(max_length=128)
    created_at = fields.DatetimeField(auto_now_add=True)

    event: fields.OneToOneRelation["Event"] = fields.OneToOneField(
        "models.Event", on_delete=fields.OnDelete.CASCADE, related_name="address", pk=True
    )

    class Meta:
        ordering = ["city"]


class Team(Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()
    created_at = fields.DatetimeField(auto_now_add=True)

    events: fields.ManyToManyRelation["Event"]

    class Meta:
        ordering = ["name"]

1. 模型关联的定义

# 原始:

participants: fields.ManyToManyRelation[Team]

# 修改为:

participants: fields.ManyToManyRelation["Team"]

# 这样和其它模型定义关联保持一致,更容易理解

2. 关于示例模型的理解

官方示例很说明问题,其中涵盖了基本的表结构定义模式,已经双向引用的模式定义,具体使用方式参考官文就可以

Getting started - Tortoise ORM v0.20.0 Documentation

3. 使用ORM模块提供的Pydantic数据抽象模块

后续的例子会提供,从网上看到大多数教程大都自定义映射,繁琐且容易出错

4. 生成的数据表

通过创建的表和表结构,ORM为我们创建好了各种表和对应的关

模型测试

async def run():
    await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})
    await Tortoise.generate_schemas()

    Event_Pydantic = pydantic_model_creator(Event)
    Event_Pydantic_List = pydantic_queryset_creator(Event)
    Tournament_Pydantic = pydantic_model_creator(Tournament)
    Team_Pydantic = pydantic_model_creator(Team)

    Address_Pydantic = pydantic_model_creator(Address)

    tournament = await Tournament.create(name="New Tournament")
    tournament2 = await Tournament.create(name="Old Tournament")
    await Event.create(name="Empty")
    event = await Event.create(name="Test", tournament=tournament)
    event2 = await Event.create(name="TestLast", tournament=tournament)
    event3 = await Event.create(name="Test2", tournament=tournament2)
    await Address.create(city="Santa Monica", street="Ocean", event=event)
    await Address.create(city="Beijing", street="G6", event=event2)
    team1 = await Team.create(name="Onesies")
    team2 = await Team.create(name="T-Shirts")
    team3 = await Team.create(name="Alternates")
    await event.participants.add(team1, team2, team3)
    await event2.participants.add(team1, team2)
    await event3.participants.add(team1, team3)

    p = await Event_Pydantic.from_tortoise_orm(await Event.get(name="Test"))
    print("基于Event 'One Event:' \n", p.model_dump_json(indent=4))

    p = await Address_Pydantic.from_tortoise_orm(await Address.all().first())
    print("基于Address 'One Address:' \n", p.model_dump_json(indent=4))
    #
    p = await Tournament_Pydantic.from_tortoise_orm(await Tournament.get(name="New Tournament"))
    print("基于 Tournament 'One Tournament:'\n", p.model_dump_json(indent=4))
    #
    p = await Team_Pydantic.from_tortoise_orm(await Team.get(name="Onesies"))
    print("基于 Team 'One Team:' \n", p.model_dump_json(indent=4))
    #
    pl = await Event_Pydantic_List.from_queryset(Event.filter(address__event_id__isnull=True))
    print("All Events without addresses: \n", pl.model_dump_json(indent=4))


if __name__ == "__main__":
    run_async(run())

执行结果

基于Event 'One Event:'?
?{
? ? "id": 2,
? ? "name": "Test",
? ? "created_at": "2024-01-18T07:25:49.256352Z",
? ? "tournament": {
? ? ? ? "id": 1,
? ? ? ? "name": "New Tournament",
? ? ? ? "created_at": "2024-01-18T07:25:49.255311Z"
? ? },
? ? "participants": [
? ? ? ? {
? ? ? ? ? ? "id": 3,
? ? ? ? ? ? "name": "Alternates",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.259313Z"
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? "id": 1,
? ? ? ? ? ? "name": "Onesies",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z"
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? "id": 2,
? ? ? ? ? ? "name": "T-Shirts",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.259313Z"
? ? ? ? }
? ? ],
? ? "address": {
? ? ? ? "city": "Santa Monica",
? ? ? ? "street": "Ocean",
? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z",
? ? ? ? "event_id": 2
? ? }
}

基于Address 'One Address:'?
?{
? ? "city": "Beijing",
? ? "street": "G6",
? ? "created_at": "2024-01-18T07:25:49.258312Z",
? ? "event": {
? ? ? ? "id": 3,
? ? ? ? "name": "TestLast",
? ? ? ? "created_at": "2024-01-18T07:25:49.257311Z",
? ? ? ? "tournament": {
? ? ? ? ? ? "id": 1,
? ? ? ? ? ? "name": "New Tournament",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.255311Z"
? ? ? ? },
? ? ? ? "participants": [
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? "name": "Onesies",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z"
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "id": 2,
? ? ? ? ? ? ? ? "name": "T-Shirts",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.259313Z"
? ? ? ? ? ? }
? ? ? ? ]
? ? },
? ? "event_id": 3
}

基于 Tournament 'One Tournament:'
?{
? ? "id": 1,
? ? "name": "New Tournament",
? ? "created_at": "2024-01-18T07:25:49.255311Z",
? ? "events": [
? ? ? ? {
? ? ? ? ? ? "id": 2,
? ? ? ? ? ? "name": "Test",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.256352Z",
? ? ? ? ? ? "participants": [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 3,
? ? ? ? ? ? ? ? ? ? "name": "Alternates",
? ? ? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.259313Z"
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? ? ? "name": "Onesies",
? ? ? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z"
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 2,
? ? ? ? ? ? ? ? ? ? "name": "T-Shirts",
? ? ? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.259313Z"
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ],
? ? ? ? ? ? "address": {
? ? ? ? ? ? ? ? "city": "Santa Monica",
? ? ? ? ? ? ? ? "street": "Ocean",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z",
? ? ? ? ? ? ? ? "event_id": 2
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? "id": 3,
? ? ? ? ? ? "name": "TestLast",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.257311Z",
? ? ? ? ? ? "participants": [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? ? ? "name": "Onesies",
? ? ? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z"
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? "id": 2,
? ? ? ? ? ? ? ? ? ? "name": "T-Shirts",
? ? ? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.259313Z"
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ],
? ? ? ? ? ? "address": {
? ? ? ? ? ? ? ? "city": "Beijing",
? ? ? ? ? ? ? ? "street": "G6",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z",
? ? ? ? ? ? ? ? "event_id": 3
? ? ? ? ? ? }
? ? ? ? }
? ? ]
}

基于 Team 'One Team:'?
?{
? ? "id": 1,
? ? "name": "Onesies",
? ? "created_at": "2024-01-18T07:25:49.258312Z",
? ? "events": [
? ? ? ? {
? ? ? ? ? ? "id": 2,
? ? ? ? ? ? "name": "Test",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.256352Z",
? ? ? ? ? ? "tournament": {
? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? "name": "New Tournament",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.255311Z"
? ? ? ? ? ? },
? ? ? ? ? ? "address": {
? ? ? ? ? ? ? ? "city": "Santa Monica",
? ? ? ? ? ? ? ? "street": "Ocean",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z",
? ? ? ? ? ? ? ? "event_id": 2
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? "id": 4,
? ? ? ? ? ? "name": "Test2",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.257311Z",
? ? ? ? ? ? "tournament": {
? ? ? ? ? ? ? ? "id": 2,
? ? ? ? ? ? ? ? "name": "Old Tournament",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.255311Z"
? ? ? ? ? ? },
? ? ? ? ? ? "address": null
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? "id": 3,
? ? ? ? ? ? "name": "TestLast",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.257311Z",
? ? ? ? ? ? "tournament": {
? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? "name": "New Tournament",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.255311Z"
? ? ? ? ? ? },
? ? ? ? ? ? "address": {
? ? ? ? ? ? ? ? "city": "Beijing",
? ? ? ? ? ? ? ? "street": "G6",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z",
? ? ? ? ? ? ? ? "event_id": 3
? ? ? ? ? ? }
? ? ? ? }
? ? ]
}

All Events without addresses:?
?[
? ? {
? ? ? ? "id": 1,
? ? ? ? "name": "Empty",
? ? ? ? "created_at": "2024-01-18T07:25:49.256352Z",
? ? ? ? "tournament": null,
? ? ? ? "participants": [],
? ? ? ? "address": null
? ? },
? ? {
? ? ? ? "id": 4,
? ? ? ? "name": "Test2",
? ? ? ? "created_at": "2024-01-18T07:25:49.257311Z",
? ? ? ? "tournament": {
? ? ? ? ? ? "id": 2,
? ? ? ? ? ? "name": "Old Tournament",
? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.255311Z"
? ? ? ? },
? ? ? ? "participants": [
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "id": 3,
? ? ? ? ? ? ? ? "name": "Alternates",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.259313Z"
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "id": 1,
? ? ? ? ? ? ? ? "name": "Onesies",
? ? ? ? ? ? ? ? "created_at": "2024-01-18T07:25:49.258312Z"
? ? ? ? ? ? }
? ? ? ? ],
? ? ? ? "address": null
? ? }
]
?

文章来源:https://blog.csdn.net/wzbhbb/article/details/135668436
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。