1

如何在使用 FastAPI 和 Tortoise-ORM 时使用 ForeignKey 关系并以 json 形式返回它们?

我知道如何直接使用 TortoiseORM 来实现它们,但是在尝试通过 FastAPI 执行相同操作时失败了。我的模式没有显示任何一种关系,而且我也不知道如何创建/更新对象以通过 HTTP/JSON 表示此信息。

Bellow 遵循一个带有简单模型的小型运行代码(两个元素,一个简单的关系和整个 FastAPI 样板来获取/放置/发布对象。该代码需要先安装tortoise-orm fastapiuvicorn。要运行它,只需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 上运行良好。

4

0 回答 0