You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pydantic多继承异常:UserAPI模型未包含自定义_id字段

问题:Pydantic多继承后自定义字段丢失

问题场景

定义了用于请求响应处理的BaseSchema和MongoDB文档配置的BaseDocument,通过继承构建UserAPI模型,期望在UserBase基础上添加_id字段用于API输出,但实际生成的Schema中仅包含UserBase的字段,_id字段缺失。

相关代码:

from datetime import datetime, timezone
from typing import Any

from beanie import Document
from pydash import camel_case
from pydantic import BaseModel, Extra


def format_datetime_into_isoformat(timestamp: datetime) -> str:
    return timestamp.replace(tzinfo=timezone.utc).isoformat().replace("+00:00", "Z")


def format_dict_key_to_camel_case(key: str) -> str:
    return camel_case(key)


class BaseDocument(BaseModel):
    class Config:
        orm_mode: bool = True
        use_enum_values: bool = True
        validate_assignment: bool = True
        allow_population_by_field_name: bool = True
        json_encoders: dict = {datetime: format_datetime_into_isoformat}


class BaseSchema(BaseModel):
    class Config:
        extra = Extra.forbid
        allow_population_by_field_name: bool = True
        alias_generator: Any = format_dict_key_to_camel_case


class UserBase(BaseDocument):
    user_name: str
    email: str
    password: str


class User(Document, UserBase):
    class Settings:
        name = "users"
        indexes = ["user_name", "email"]


class UserAPI(BaseSchema, UserBase):
    _id: str

生成的Schema(缺失_id):

{'title': 'UserAPI', 'type': 'object', 'properties': {'userName': {'title': 'Username', 'type': 'string'}, 'email': {'title': 'Email', 'type': 'string'}, 'password': {'title': 'Password', 'type': 'string'}}, 'required': ['userName', 'email', 'password'], 'additionalProperties': False}

原因分析

  1. 多继承顺序影响字段合并:UserAPI先继承BaseSchema再继承UserBase,Pydantic的方法解析顺序(MRO)会优先处理BaseSchema的配置,导致子类自定义的_id字段未被正确纳入字段集合。
  2. 字段别名转换:BaseSchema中的alias_generator会将_id转换为id,但原代码未意识到这一点,误以为字段完全丢失。

解决方案

方案1:调整继承顺序

将UserBase放在继承顺序首位,确保通用字段先加载,再应用BaseSchema的配置:

class UserAPI(UserBase, BaseSchema):
    _id: str

此时生成的Schema中,_id会被转换为驼峰命名的id字段,符合API响应的命名规范。

方案2:显式指定字段别名

如果需要保留_id作为响应字段名,可通过Field显式指定别名,避免被alias_generator转换:

from pydantic import Field

class UserAPI(BaseSchema, UserBase):
    _id: str = Field(..., alias="_id")

方案3:修改别名生成规则

在format_dict_key_to_camel_case函数中排除对_id的转换,保留原字段名:

def format_dict_key_to_camel_case(key: str) -> str:
    if key == "_id":
        return key
    return camel_case(key)

验证

调整后执行print(UserAPI.schema()),即可看到包含_id或id字段的完整Schema。

内容的提问来源于stack exchange,提问作者Md Abdur Rakib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:25:43