Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
265 views
in Technique[技术] by (71.8m points)

Python pydantic, make every field of ancestor are Optional

I have 2 classes:

class UserCreate(BaseModel):
    avatar: HttpUrl = Field(..., description="Avatar", example="https://picsum.photos/200")
    name: str = Field(..., max_length=20, description="A single word", example='Ivan')
    birthdate: datetime_date = Field(..., description="Two digits", example='1980-1-1')
    comment: Optional[str] = Field(..., max_length=512, description="lorem ipsum about a user", example='blah blah')

and I want to create a UserUpdate class that will inherit every field from the parent class and make it Optional.

a Result class must look like:

class UserUpdate(BaseModel):
    avatar: typing.Optional[HttpUrl] = Field(..., description="Avatar", example="https://picsum.photos/200")
    name: typing.Optional[str] = Field(..., max_length=20, description="A single word", example='Ivan')
    birthdate: typing.Optional[datetime_date] = Field(..., description="Two digits", example='1980-1-1')
    comment: typing.Optional[str] = Field(..., max_length=512, description="lorem ipsum about a user", example='blah blah')

But obviously, I want to make it automatically, like:

class UserUpdate(UserCreate):
    def foo(fields_from_user_create):
        for fields in fields_from_user_create:
            field = typing.Optional(field)
question from:https://stackoverflow.com/questions/65836195/python-pydantic-make-every-field-of-ancestor-are-optional

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A solution directly from PrettyWood

Here is a way of doing it

from copy import deepcopy
from typing import Optional, Type, TypeVar

from pydantic import BaseModel, create_model

BaseModelT = TypeVar('BaseModelT', bound=BaseModel)


def to_optional(model: Type[BaseModelT], name: Optional[str] = None) -> Type[BaseModelT]:
    """
    Create a new BaseModel with the exact same fields as `model`
    but making them all optional
    """
    field_definitions = {}

for name, field in model.__fields__.items():
    optional_field_info = deepcopy(field.field_info)
    # Do not change default value of fields that are already optional
    if optional_field_info.default is ...:
        optional_field_info.default = None
    field_type = model.__annotations__.get(name, field.outer_type_)
    field_definitions[name] = (field_type, optional_field_info)

return create_model(name or f'Optional{model.__name__}', **field_definitions)  # type: ignore[arg-type]

Hope it helps ;)

Original answer


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...