如何在使用 FastAPI 和 Tortoise-ORM 时使用 ForeignKey 关系并以 json 形式返回它们?
我知道如何直接使用 TortoiseORM 来实现它们,但是在尝试通过 FastAPI 执行相同操作时失败了。我的模式没有显示任何一种关系,而且我也不知道如何创建/更新对象以通过 HTTP/JSON 表示此信息。
Bellow 遵循一个带有简单模型的小型运行代码(两个元素,一个简单的关系和整个 FastAPI 样板来获取/放置/发布对象。该代码需要先安装tortoise-orm
fastapi
和uvicorn
。要运行它,只需python main.py
(文件必须是命名main.py
,否则uvicorn.run
调用将失败)。
# Requires: tortoise-orm, fastapi, uvicorn
from typing import List
import Tortoise
from fastapi import FastAPI
from tortoise.models import Model
from tortoise.fields import (
IntField,
CharField,
ForeignKeyField,
DatetimeField,
ReverseRelation,
)
from tortoise.contrib.fastapi import register_tortoise
from tortoise.contrib.pydantic.creator import (
pydantic_model_creator,
pydantic_queryset_creator,
)
class Toy(Model):
id = IntField(pk=True)
name = CharField(max_length=32, null=False)
owner = ForeignKeyField("models.Person", null=True, related_name="toys_own")
created_at = DatetimeField(auto_now_add=True)
updated_at = DatetimeField(auto_now=True)
class Person(Model):
id = IntField(pk=True)
name = CharField(max_length=32, null=False)
toys_own: ReverseRelation["Toy"]
ToySchema = pydantic_model_creator(Toy, name="Toy")
ToySchemaIn = pydantic_model_creator(Toy, name="ToyIn", exclude_readonly=True)
ToySchema_List = pydantic_queryset_creator(Toy)
PersonSchema = pydantic_model_creator(Person, name="Person")
PersonSchemaIn = pydantic_model_creator(Person, name="PersonIn", exclude_readonly=True)
PersonSchema_List = pydantic_queryset_creator(Person)
app = FastAPI()
async def init():
Tortoise.init_models(["main"], "models")
register_tortoise(
app,
db_url="sqlite://:memory:",
modules={"models": ["main"]},
generate_schemas=True,
add_exception_handlers=True,
)
print(ToySchema.schema_json(indent=4))
print(PersonSchema.schema_json(indent=4))
@app.on_event("startup")
async def startup_event():
await init()
@app.get("/toy/{toy_id}", response_model=ToySchema)
async def get_toy(toy_id: int):
return await Toy.get(id=toy_id)
@app.get("/toy/", response_model=List[ToySchema])
async def get_all_toys():
return await Toy.all()
@app.post("/toy", response_model=ToySchema)
async def create_toy(toy: ToySchemaIn):
return await Toy.create(**toy.dict(exclude_unset=True))
@app.put("/toy/{toy_id}", response_model=ToySchema)
async def update_toy(toy_id: int, toy: ToySchemaIn):
await Toy.filter(id=toy_id).update(**toy.dict(exclude_unset=True))
return await Toy.get(id=toy_id)
@app.get("/person/{person_id}", response_model=PersonSchema)
async def get_person(person_id: int):
return await PersonSchema.from_queryset_single(Person.get(id=person_id))
@app.get("/person/", response_model=List[PersonSchema])
async def get_all_persons():
return await PersonSchema.from_queryset(Person.all())
@app.post("/person", response_model=PersonSchema)
async def create_person(person: PersonSchemaIn):
person_ = await Person.create(**person.dict(exclude_unset=True))
return await PersonSchema.from_tortoise_orm(person_)
@app.put("/person/{person_id}", response_model=PersonSchema)
async def update_person(person_id: int, person: PersonSchemaIn):
await Person.filter(id=person_id).update(**person.dict(exclude_unset=True))
return await PersonSchema.from_queryset_single(Person.get(id=person_id))
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="127.0.0.1", port=8888, reload=True)
此外,为了更简单的测试,使用一个小的 bash 脚本来创建/更新一些对象。
echo -e "\n\nCreate one toy: "
curl -X 'POST' \
'http://127.0.0.1:8888/toy' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"name\": \"Pinocchio ${RANDOM}\"
}"
echo -e "\n\nUPDATE one toy: "
curl -X 'PUT' \
'http://127.0.0.1:8888/toy/1' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"name\": \"SidEdit ${RANDOM}\"
}"
echo -e "\n\nGet all toys"
curl -X 'GET' \
'http://127.0.0.1:8888/toy/' \
-H 'accept: application/json'
echo -e "\n\nCreate one person: "
curl -X 'POST' \
'http://127.0.0.1:8888/person' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"name\": \"John ${RANDOM}\"
}"
echo -e "\n\nUPDATE one person: "
curl -X 'PUT' \
'http://127.0.0.1:8888/person/1' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"name\": \"MaryEdit ${RANDOM}\"
}"
echo -e "\n\nGet all persons"
curl -X 'GET' \
'http://127.0.0.1:8888/person/' \
-H 'accept: application/json'
此代码段在 Python 3.9、Tortoise ORM 0.17.8 和 FastAPI 0.70.0 上运行良好。