正在进入ing...

tortoise-orm进阶使用说明

发布时间:2023-11-28 浏览量: 1750 文章分类: python

tortoise-orm进阶使用说明

之前我写了一篇关于tortoise-orm的简单教程tortoise-orm看着一篇足够你入门,有小伙伴找我一直在说感觉教程写的不清晰、不全面,实际上一篇主要还是在配置和使用上做了说明,并没有深入去讲解,主要原因是因为后面我发现了sqlaichemy2.x系列的也支持异步了,所以有一段时间就回去用sqlaichemy2.x了,不过最近在做一个新的项目时,也想起来了tortoise-orm,那就在用起来,同时顺带把 一对多多对多关系整理一下,做一个备忘和说明。

废话不多说,直接开始吧

使用环境

tortoise-orm      0.20.0
pydantic          2.5.2
pydantic_core     2.14.5
fastapi           0.104.1

项目结构

这次不整那么复杂的了,我们就简单通过一个例子来涵盖整体的使用。

# models.py

class Tags(Model):
    name = fields.CharField(max_length=30)

class Author(Model):
    name = fields.CharField(max_length=100)

class Book(Model):
    name = fields.CharField(max_length=80)
    author = fields.ForeignKeyField('models.Author',related_name='author')
    tag = fields.ManyToManyField('models.Tags',related_name='tag')

上面我建了3个类型,书的类型(Tags)、作者(Author)、书(Book) 那么 一本书会有一个作者、但是可能有多个类型

比如下面这样

书名 作者 类型
斗破苍穹 天蚕土豆 玄幻、穿越
星辰变 我吃西红柿 仙侠、玄幻
盘龙 我吃西红柿 奇幻、魔法
  • 书针对作者就是 一对多关系author = fields.ForeignKeyField('models.Author',related_name='author'),一个作者可以写多本书
  • 书对于类型就是多对多关系fields.ManyToManyField('models.Tags',related_name='tag'),一本书可以有N个类型,既是玄幻,也是魔法 或者穿越 都是可以。

既然也都用上了fastAPI,那顺带吧pydantic也一起写了,便于验证。

class TagsPydantic(BaseModel):
    name:str = Field(max_length=20)

class AuthorPydantic(BaseModel):
    name:str = Field(max_length=100)

class BookPydantic(BaseModel):
    name:str = Field(max_length=100)
    author_id:int = Field()
    tags_id:List[int]

视图函数

这里对于作者、类型的添加我就不讲了,非常简单,常规添加就好,着重说的重点就是关于书(Book)的添加。

# 查询tag列表
@app.get('/get_tag')
async def get_tag():
    tags_obj = await Tags.all()
    return tags_obj
# 创建一个tag
@app.post('/add_tag')
async def add_tag(post_data:TagsPydantic):
    result = await Tags.create(**post_data.model_dump())
    return result
# 查询作者列表
@app.get('/get_author')
async def get_author():
    authors_obj = await Author.all()
    return  authors_obj
# 写入一个作者
@app.post('/add_author')
async def add_author(req:Request,post_data:AuthorPydantic):
    result = await Author.create(**post_data.model_dump())
    return result
# 查询书籍列表
@app.get('/get_book')
async def get_books():
    books_obj = await Book.all()
    for book in books_obj:
        print(book.name) # 这里要注意返回的结果是不会带多对多关系的
        author_obj = await book.author
        print(author_obj.name)
        for tag in await book.tag.all():
            print(tag.name)
        print("-"*10)
    return books_obj

@app.post('/add_book')
async def add_book(post_data:BookPydantic):
    print(post_data)
    book_obj = await Book.create(**post_data.model_dump())
    # 处理多对多
    for tag in post_data.tags_id:
        tag_obj = await Tags.filter(id=tag).first()
        await book_obj.tag.add(tag_obj)

    return book_obj

此时我们调用add_tag可以创建如下数据

[
    {
        "name": "玄幻",
        "id": 1
    },
    {
        "name": "穿越",
        "id": 2
    },
    {
        "name": "仙侠",
        "id": 3
    },
    {
        "name": "奇幻",
        "id": 4
    },
    {
        "name": "魔法",
        "id": 5
    }
]

继续调用add_author创建作者

[
    {
        "name": "天蚕土豆",
        "id": 1
    },
    {
        "name": "我吃西红柿",
        "id": 2
    }
]

接着就是创建书籍了add_book我们传入{"name":"斗破苍穹","author_id":1,"tags_id":[1,2]}就可以创建一本名字叫斗破苍穹,作者是天蚕土豆,分类分别是玄幻穿越属性的书籍信息。

截止到这里,对最常见使用的 getcreate两个方法在tortoise-orm的使用就说明完毕了,接下来继续是关于updatedelete的方法。

假设现在有个需求,我们想让修改书籍的作者或类型。那我们继续实现下面的函数。

@app.put('/update_book/{book_id}')
async def update_book(*,book_id:int,post_data:BookPydantic):
    # 先找到对应要修改的对象类型
    book_obj = await Book.filter(id=book_id).first()
    # 修改数据内容
    book_obj.update_from_dict(post_data.model_dump())

    # 由于多对多涉及中间表,我的思路是先清空,在重新设置上
    await book_obj.tag.clear()
    for tag_id in post_data.tags_id:
        tag_obj = await Tags.filter(id=tag_id).first()
        book_obj.tag.add(tag_obj)
    await book_obj.save()
    return None

常规的update到没什么好讲的,基本都是一样的用法,不过tortoise-ormupdate_from_dict感觉用的场景和频率会更高一些,这里就用他来举例了。