tortoise-orm进阶使用说明
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]}就可以创建一本名字叫斗破苍穹,作者是天蚕土豆,分类分别是玄幻、穿越属性的书籍信息。
截止到这里,对最常见使用的 get、create两个方法在tortoise-orm的使用就说明完毕了,接下来继续是关于update和delete的方法。
假设现在有个需求,我们想让修改书籍的作者或类型。那我们继续实现下面的函数。
@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-orm的update_from_dict感觉用的场景和频率会更高一些,这里就用他来举例了。