微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Tortoise-ORM + FastAPI 中未显示模型关系

如何解决Tortoise-ORM + FastAPI 中未显示模型关系

我正在使用 Tortoise-ORM 作为它的 orm 来玩 FastAPI 并遇到了问题。具体来说,我无法在模型中返回关系。

这是我的应用程序结构。 Structure 的灵感来自 Django 的应用程序结构。

.
├── Dockerfile
├── LICENSE
├── Pipfile
├── Pipfile.lock
├── README.md
├── app
│   ├── contacts
│   │   ├── __init__.py
│   │   ├── main.py
│   │   ├── models.py
│   │   └── routers.py
│   ├── main.py
│   ├── resources
│   │   ├── __init__.py
│   │   ├── constants.py
│   │   ├── core_model.py
│   │   ├── database.py
│   │   └── middlewares.py
│   └── users
│       ├── __init__.py
│       ├── main.py
│       ├── models.py
│       └── routers.py
└── docker-compose.yml

数据库连接在 app/resources/database.py 中设置如下;

from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise


def get_db_uri(*,user,password,host,db):
    return f'postgres://{user}:{password}@{host}:5432/{db}'


def setup_database(app: FastAPI):
    register_tortoise(
        app,db_url=get_db_uri(
            user='postgres',password='postgres',host='db',# docker-compose service name
            db='postgres',),modules={
            'models': [
                'app.users.models','app.contacts.models',],},generate_schemas=True,add_exception_handlers=True,)

models 参数中您可以看到有 2 个模型设置。这是两个。

app/users/models.py

from tortoise import Tortoise,fields
from tortoise.contrib.pydantic import pydantic_model_creator
from passlib.hash import bcrypt

from app.resources.core_model import CoreModel


class User(CoreModel):
    username = fields.CharField(50,unique=True)
    email = fields.CharField(60,unique=True)
    password_hash = fields.CharField(128)

    def __str__(self):
        return self.email

    def verify_password(self,password):
        return bcrypt.verify(password,self.password_hash)

    class PydanticMeta:
        exclude = ["password_hash"]


# Tortoise.init_models(['app.users.models'],'models')

User_Pydantic = pydantic_model_creator(User,name='User')
UserIn_Pydantic = pydantic_model_creator(
    User,name='UserIn',exclude_readonly=True)

app/contacts/models.py

from tortoise import Tortoise,fields
from tortoise.contrib.pydantic import pydantic_model_creator

from app.resources.core_model import CoreModel


class Contact(CoreModel):
    user = fields.ForeignKeyField(
        'models.User',related_name='contacts')
    name = fields.CharField(50)

    def __str__(self):
        return self.name


# Tortoise.init_models(['app.users'],'models')


Contact_Pydantic = pydantic_model_creator(Contact,name='Contact')
ContactIn_Pydantic = pydantic_model_creator(
    Contact,name='ContactIn',exclude_readonly=True)

以下是用户尝试保存联系人时发生的情况。

@router.post('/',status_code=status.HTTP_201_CREATED)
async def create_contact(contact_name: str = Form(...),user: User_Pydantic = Depends(get_current_user)):
    try:
        contact = Contact(user_id=user.id,name=contact_name)
        await contact.save()
        contact_obj = await Contact_Pydantic.from_tortoise_orm(contact)
        print(contact_obj.schema_json(indent=4))
    except Exception as err:
        print(err)
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,detail='Failed to save data')
    return {'status_code': status.HTTP_201_CREATED,'contact': contact_obj.dict()}

用户可以从以下路线检索他们保存的联系人。

@router.get('/me')
async def get_all_contacts(user: User_Pydantic = Depends(get_current_user)):
    try:
        contacts = await Contact.filter(user_id=user.id)
        contacts_list = [await Contact_Pydantic.from_tortoise_orm(contact) for contact in contacts]
        print(user.schema_json())
    except:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,detail='Failed to fetch related data')
    return {'contacts': contacts_list}

用户检索他们的联系人时,它不会显示用户的关系。在这个例子中,它不是必需的,但我想弄清楚如何在响应中获取关系以供将来参考。

我浏览了文档,发现 early-init一个东西,并尝试使用 init_models 但这似乎不起作用。或者也许我只是不知道它是如何工作的。如果我需要使用 init_models,令人困惑的部分是 1. 何时调用它和 2. 如何调用它。 init_models 两个论点让我很困惑。

总结一下,我有两个问题。

  1. 如何从模型中获取关系并将其返回给用户
  2. 如果我需要使用 init_models,我在哪里调用它以及使用此应用程序结构的 2 个必需参数的正确方法是什么。

提前致谢。

注意

  1. 我尝试了以下方法来保存联系人,但结果是一样的。
@router.post('/',user: User_Pydantic = Depends(get_current_user)):
    try:
        user = await User.get(id=user.id)
        contact = await Contact.create(user=user,name=contact_name)
        contact_obj = await Contact_Pydantic.from_tortoise_orm(contact)
        print(contact_obj.schema_json(indent=4))
    except Exception as err:
        print(err)
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,'contact': contact_obj.dict()}

解决方法

感谢@alex_noname,我可以做到这一点。

首先,将 pydantic 模式与 models.py 分开。

.
├── Dockerfile
├── LICENSE
├── Pipfile
├── Pipfile.lock
├── README.md
├── app
│   ├── contacts
│   │   ├── __init__.py
│   │   ├── main.py
│   │   ├── models.py
│   │   ├── routers.py
│   │   └── schemas.py  <- new
│   ├── main.py
│   ├── resources
│   │   ├── __init__.py
│   │   ├── constants.py
│   │   ├── core_model.py
│   │   ├── database.py
│   │   └── middlewares.py
│   └── users
│       ├── __init__.py
│       ├── main.py
│       ├── models.py
│       ├── routers.py
│       └── schemas.py  <- new
└── docker-compose.yml

app/users/schemas.py

from tortoise.contrib.pydantic import pydantic_model_creator

from .models import User


User_Pydantic = pydantic_model_creator(User,name='User')
UserIn_Pydantic = pydantic_model_creator(
    User,name='UserIn',exclude_readonly=True)

app/contacts/schemas.py

from tortoise.contrib.pydantic import pydantic_model_creator

from .models import Contact


Contact_Pydantic = pydantic_model_creator(Contact,name='Contact')
ContactIn_Pydantic = pydantic_model_creator(
    Contact,name='ContactIn',exclude_readonly=True)

然后,在我们设置 tortoise-orm 的 app/resources/database.py 中,调用 init_models

from fastapi import FastAPI
from tortoise import Tortoise
from tortoise.contrib.fastapi import register_tortoise


def get_db_uri(*,user,password,host,db):
    return f'postgres://{user}:{password}@{host}:5432/{db}'


def setup_database(app: FastAPI):
    register_tortoise(
        app,db_url=get_db_uri(
            user='postgres',password='postgres',host='db',# docker-composeのservice名
            db='postgres',),modules={
            'models': [
                'app.users.models','app.contacts.models',],},# modules={"models": ["_models_"]},generate_schemas=True,add_exception_handlers=True,)


Tortoise.init_models(['app.users.models','app.contacts.models'],'models')  # <- added

就是这样!
这就像一个魅力。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。