如何扩展一个 pydantic 对象并更改某些字段的类型?
How to extend a pydantic object and change some fileds' type?
有两个类似的玩世不恭的对象。唯一的区别是一些字段是可选的。
我怎样才能只定义一个对象中的字段并扩展到另一个对象中?
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]
...
你自己回答的差不多了。除非有更多问题。
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
我通过 __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
或者像在这个线程中那样使用元类:
class AllOptional(pydantic.main.ModelMetaclass):
def __new__(self, name, bases, namespaces, **kwargs):
annotations = namespaces.get('__annotations__', {})
for base in bases:
annotations.update(base.__annotations__)
for field in annotations:
if not field.startswith('__') and field != 'project_id':
annotations[field] = Optional[annotations[field]]
namespaces['__annotations__'] = annotations
return super().__new__(self, name, bases, namespaces, **kwargs)
在你的例子中...
class ProjectPatchObject(ProjectCreateObject, metaclass=AllOptional):
...
有两个类似的玩世不恭的对象。唯一的区别是一些字段是可选的。 我怎样才能只定义一个对象中的字段并扩展到另一个对象中?
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]
...
你自己回答的差不多了。除非有更多问题。
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
我通过 __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
或者像在这个线程中那样使用元类:
class AllOptional(pydantic.main.ModelMetaclass):
def __new__(self, name, bases, namespaces, **kwargs):
annotations = namespaces.get('__annotations__', {})
for base in bases:
annotations.update(base.__annotations__)
for field in annotations:
if not field.startswith('__') and field != 'project_id':
annotations[field] = Optional[annotations[field]]
namespaces['__annotations__'] = annotations
return super().__new__(self, name, bases, namespaces, **kwargs)
在你的例子中...
class ProjectPatchObject(ProjectCreateObject, metaclass=AllOptional):
...