如何使用 PydanticMeta [FastAPI, Tortoise ORM]

问题描述

我目前正在开发个人财务 api,我正在努力恢复一些在 pydantic 模型中异步的函数。 我正在使用 FastApi、pydantic 和 Tortoise ORM。 基本上目的是返回给定用户的所有 Budget.amount (month_base) 的总和,但问题是这个函数是异步的,当我将它作为计算字段传递给 PydanticMeta 类时,它不会等待,因此返回值不是正确的类型,如以下错误所述:

ERROR:hypercorn.error:Asgi 框架中的错误 [...] 文件“pydantic/main.py”,第 573 行,在 pydantic.main.BaseModel.from_orm pydantic.error_wrappers.ValidationError: 1 用户验证错误 month_base 值不是有效的浮点数 (type=type_error.float)

/home/jon/ml-v3/venv/lib/python3.8/site-packages/tortoise/contrib/pydantic/base.py:88: RuntimeWarning: coroutine 'User.month_base' 从未等待

我在models.py中的代码

class SoftDeleteMixin:
    deleted = fields.BooleanField(default=False)
    deletion_date = fields.DatetimeField(null=True)

    def soft_delete(self):
        """
        Annotate the object as deleted and saves the deletion_date
        ---Return---
        False if the object is already deleted else True
        """
        if self.deleted:
            return False
        self.deleted = True
        self.deletion_date = datetime.today()
        return True

    @classmethod
    async def get_non_deleted(cls,user_id: int):
        return await cls.filter(Q(user_id=user_id) & Q(deleted=False))
    

class User(Model):
        id = fields.IntField(pk=True)
        gender = fields.IntEnumField(Gender,default=Gender.not_specified)
        configured = fields.BooleanField(default=False)
        start_date = fields.DatetimeField(null=True)
        email = fields.CharField(max_length=100,unique=True,index=True)
        full_name = fields.CharField(max_length=50)
        password_hash = fields.CharField(max_length=128,null=True)
        confirmed = fields.BooleanField(default=False)
        general_terms_and_conditions_of_sale_signed = fields.BooleanField(default=False)
        privacy_policy_signed = fields.BooleanField(default=False)
        signature_date = fields.DatetimeField(null=True)
        # One-To-Many relationships
        budgets: fields.ReverseRelation['Budget']
        origins: fields.ReverseRelation['Origin']
        long_budgets: fields.ReverseRelation['LongBudget']
        stocks: fields.ReverseRelation['Stock']
        outcomes: fields.ReverseRelation['Outcome']
        incomes: fields.ReverseRelation['Income']
        costs: fields.ReverseRelation['Cost']
        transfer: fields.ReverseRelation['Transfer']
        images: fields.ReverseRelation['Image']
    
    async def get_budgets(self):
        return await Budget.get_non_deleted(user_id=self.id).order_by('order')

    async def month_base(self) -> float:
        return sum(map(lambda budget: budget.month_budget,await self.get_budgets()))
    class PydanticMeta:
        computed = ['month_base',]
        exclude = ['password_hash','general_terms_and_conditions_of_sale_signed','privacy_policy_signed','signature_date','confirmed']

我在 schemas.py 中的代码

User = pydantic_model_creator(models.User,name='User')
UserIn = pydantic_model_creator(models.User,exclude=('configured','start_date'),name='UserIn',exclude_readonly=True)

我在 main.py 中的代码

async def get_current_user(token: str = Depends(oauth2_schema)):
    try:
        payload = jwt.decode(token,JWT_SECRET,algorithms=['HS256'])
        user = await User.get(id=payload.get('id'))
    except:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,detail='Invalid username or password'
        )
    return await sch.User.from_tortoise_orm(user)
@app.get('/user',response_model=sch.User)
async def read_user(user: sch.User = Depends(get_current_user)):
    return user

我应该如何继续将我的 month_budget 字段传递给我的用户架构,但指定给 pydanticModel 以等待其结果? 感谢您的帮助!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)