Tortoise的pydantic_model_creator未生成外键字段问题排查
问题:Tortoise-ORM生成的Pydantic模型缺失ForeignKey字段
我定义了Article和Tag两个Tortoise-ORM模型,其中Article包含指向Tag的ForeignKeyField。通过自定义的get_serialize_pydantic函数(基于tortoise.contrib.pydantic.pydantic_model_creator与Pydantic的create_model生成响应模型),但最终的响应模型仅包含title和body字段,缺失了tag字段,请问这是什么原因?
相关代码
模型定义
class Tag(MyAbstractBaseModel): name = fields.CharField(max_length=255, index=True) class Article(MyAbstractBaseModel): title = fields.CharField(max_length=255, index=True) body = fields.CharField(max_length=255) tag = fields.ForeignKeyField(model_name="Tag", related_name='article', on_delete=fields.CASCADE)
路由代码
@router.get("/article", response_model=get_serialize_pydantic(Article)) async def get(): pass
工具函数代码
from tortoise.contrib.pydantic import pydantic_model_creator from pydantic import BaseModel, Field, create_model def get_serialize_pydantic(models_obj: Type[Model], exclude: Tuple[str, ...] = None): my_model_pydantic = pydantic_model_creator(models_obj) response_pydantic = create_model( __model_name=f"{models_obj.__name__}_response_pydantic", data=(Optional[List[my_model_pydantic]], Field(None, title="data")), __base__=BaseResponse) return response_pydantic
原因分析
tortoise.contrib.pydantic.pydantic_model_creator默认参数exclude_related=True,该设置会自动排除模型中所有关联字段(包括ForeignKeyField),所以生成的Article Pydantic模型里没有tag字段。
解决方案
有三种方式可以解决这个问题:
方式一:关闭关联字段默认排除
修改get_serialize_pydantic函数中生成Pydantic模型的代码,设置exclude_related=False,即可包含所有关联字段:
def get_serialize_pydantic(models_obj: Type[Model], exclude: Tuple[str, ...] = None): # 关闭默认的关联字段排除 my_model_pydantic = pydantic_model_creator(models_obj, exclude_related=False) response_pydantic = create_model( __model_name=f"{models_obj.__name__}_response_pydantic", data=(Optional[List[my_model_pydantic]], Field(None, title="data")), __base__=BaseResponse) return response_pydantic
方式二:指定包含特定关联字段
如果只需要包含tag字段而非所有关联字段,用include参数明确指定:
def get_serialize_pydantic(models_obj: Type[Model], exclude: Tuple[str, ...] = None): # 仅包含tag字段 my_model_pydantic = pydantic_model_creator(models_obj, include=("tag",)) response_pydantic = create_model( __model_name=f"{models_obj.__name__}_response_pydantic", data=(Optional[List[my_model_pydantic]], Field(None, title="data")), __base__=BaseResponse) return response_pydantic
方式三:自定义关联字段的嵌套模型
如果需要返回tag的具体字段(而非仅ID),可以先创建Tag的Pydantic模型,再关联到Article的模型中:
def get_serialize_pydantic(models_obj: Type[Model], exclude: Tuple[str, ...] = None): Tag_Pydantic = pydantic_model_creator(Tag) # 包含tag字段并指定对应的嵌套模型 my_model_pydantic = pydantic_model_creator( models_obj, include=("tag",), model_config={"relations": {"tag": {"model": Tag_Pydantic}}} ) response_pydantic = create_model( __model_name=f"{models_obj.__name__}_response_pydantic", data=(Optional[List[my_model_pydantic]], Field(None, title="data")), __base__=BaseResponse) return response_pydantic
内容的提问来源于stack exchange,提问作者haojie
相关产品推荐
相关产品推荐

