如何在Tortoise ORM Pydantic Schema中排除字段并添加计算属性
问题
在FastAPI项目中使用Tortoise ORM,有一个Channel模型,受保护的频道包含可选的password_hash字段。希望生成API响应的频道列表时,排除password_hash字段,并新增一个计算布尔字段protected来标识频道是否受密码保护。
现有模型定义:
from tortoise import fields, models from tortoise.contrib.pydantic import pydantic_model_creator class Channel(models.Model): id = fields.IntField(pk=True) name = fields.CharField(max_length=100) password_hash = fields.CharField(max_length=128, null=True) owner = fields.ForeignKeyField('models.User', related_name='channels') ChannelSchema = pydantic_model_creator(Channel, name="Channel")
当前API响应示例:
[ { "id": 1, "name": "my channel", "password_hash": null }, { "id": 2, "name": "my protected channel", "password_hash": "$2b$..." } ]
期望的API响应:
[ { "id": 1, "name": "my channel", "protected": false }, { "id": 2, "name": "my protected channel", "protected": true } ]
尝试创建计算属性password_protected并排除password_hash,代码如下:
class Channel(models.Model): ... def password_protected(self) -> bool: return bool(self.password_hash) class PydanticMeta: computed = ["password_protected"] # exclude = ["password_hash"]
但开启排除password_hash后出现错误:
AttributeError: 'ResponseChannelSchema' object has no attribute 'password_hash'
请问如何正确在Pydantic模型中加入protected计算属性并排除password_hash字段?
解决方案
报错原因是:在PydanticMeta中排除password_hash后,生成的Pydantic模型实例不再包含该字段,而计算属性是从Pydantic实例读取password_hash,导致找不到属性报错。以下两种方法可以解决:
方法一:在ORM模型中用@property定义计算属性
直接在Channel模型中用@property装饰器定义protected属性,Tortoise的Pydantic生成器会从原始ORM模型实例读取该属性,而非Pydantic实例,因此即使排除password_hash,ORM实例仍能访问该字段:
from tortoise import fields, models from tortoise.contrib.pydantic import pydantic_model_creator class Channel(models.Model): id = fields.IntField(pk=True) name = fields.CharField(max_length=100) password_hash = fields.CharField(max_length=128, null=True) owner = fields.ForeignKeyField('models.User', related_name='channels') @property def protected(self) -> bool: return bool(self.password_hash) class PydanticMeta: computed = ["protected"] exclude = ["password_hash"] ChannelSchema = pydantic_model_creator(Channel, name="Channel")
方法二:自定义Pydantic模型处理字段
如果不想修改ORM模型,可以生成基础Pydantic模型后,自定义响应模型,通过computed_field计算protected并排除password_hash:
from tortoise import fields, models from tortoise.contrib.pydantic import pydantic_model_creator from pydantic import computed_field class Channel(models.Model): id = fields.IntField(pk=True) name = fields.CharField(max_length=100) password_hash = fields.CharField(max_length=128, null=True) owner = fields.ForeignKeyField('models.User', related_name='channels') # 生成包含所有字段的基础模型 BaseChannelSchema = pydantic_model_creator(Channel, name="BaseChannel") # 自定义响应模型 class ChannelSchema(BaseChannelSchema): @computed_field(return_type=bool) def protected(self) -> bool: return bool(self.password_hash) class Config: exclude = ["password_hash"]
内容的提问来源于stack exchange,提问作者Rakhmatulin
相关产品推荐
相关产品推荐

