4

有两个类似的 pydantic 对象。唯一的区别是某些字段是可选的。如何在一个对象中定义字段并扩展到另一个对象?

class ProjectCreateObject(BaseModel):
    project_id: str
    project_name: str
    project_type: ProjectTypeEnum
    depot: str
    system: str
    ...

class ProjectPatchObject(ProjectCreateObject):
    project_id: str
    project_name: Optional[str]
    project_type: Optional[ProjectTypeEnum]
    depot: Optional[str]
    system: Optional[str]
    ...

4

2 回答 2

4

我找到了一个好而简单的方法__init__subclass__。文档也可以成功生成。

class ProjectCreateObject(BaseModel):
    project_id: str
    project_name: str
    project_type: ProjectTypeEnum
    depot: str
    system: str
    ...

    def __init_subclass__(cls, optional_fields=None, **kwargs):
        """
        allow some fields of subclass turn into optional
        """
        super().__init_subclass__(**kwargs)
        if optional_fields:
            for field in optional_fields:
                cls.__fields__[field].outer_type_ = Optional
                cls.__fields__[field].required = False

_patch_fields = ProjectCreateObject.__fields__.keys() - {'project_id'}

class ProjectPatchObject(ProjectCreateObject, optional_fields=_patch_fields):
    pass

于 2020-06-02T12:18:27.440 回答
3

你自己已经回答得差不多了。除非问题还有更多。

from typing import Optional
from pydantic import BaseModel


class ProjectCreateObject(BaseModel):
    project_id: str
    project_name: str
    project_type: str
    depot: str
    system: str


class ProjectPatchObject(ProjectCreateObject):
    project_name: Optional[str]
    project_type: Optional[str]
    depot: Optional[str]
    system: Optional[str]


if __name__ == "__main__":
    p = ProjectCreateObject(
        project_id="id",
        project_name="name",
        project_type="type",
        depot="depot",
        system="system",
    )
    print(p)

    c = ProjectPatchObject(project_id="id", depot="newdepot")
    print(c)

运行这个给出:

project_id='id' project_name='name' project_type='type' depot='depot' system='system'
project_id='id' project_name=None project_type=None depot='newdepot' system=None

另一种看待它的方法是将基础定义为可选,然后创建一个验证器来检查何时都需要:

from pydantic import BaseModel, root_validator, MissingError

class ProjectPatchObject(BaseModel):
    project_id: str
    project_name: Optional[str]
    project_type: Optional[str]
    depot: Optional[str]
    system: Optional[str]


class ProjectCreateObject(ProjectPatchObject):
    @root_validator
    def check(cls, values):
        for k, v in values.items():
            if v is None:
                raise MissingError()
        return values
于 2020-05-26T20:31:54.263 回答