-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Construct does not recursively construct BaseModel? #3471
Comments
I edited the post for clarify, I realised I written does when I meant does not. |
You may read the document.
construct method is not run the validation so that this behavior is correct, I think. |
I'd argue that this is about type casting, not validation. Perhaps I can submit a PR to at least document that? |
I'm not maintainer so maybe something wrong. |
I already discovered that. Construct method do not recursively transform raw data to instances of nested classes inheriting BaseModel. Basically either you instantiate your object with parse_obj or the constructor and it must run validators or you consider that your input data is already valid AND parsed (i.e: it contains instances of your nested models if any) By the way I would really like a « recursive » construct method as well |
This is not a bug but intended behaviour, see duplicate here: #1168 I agree that documentation of |
I'll make a note on our v2 documentation plan that we should document this better. In general it's hard to draw a line on what should be done automatically or not in a construct function; we've chosen the approach that offers the best possible performance when you know you have attributes that are ready for use. If you want an "intermediate" version that will construct field values without doing any validation besides packaging dicts into models, I would recommend implementing that as a method on a shared base class that calls things recursively. |
In #6121 I have updated the docs for @samuelcolvin has mentioned potentially moving the |
@dmontagu on the other hand fixing this in Python now is close to trivial @@ -472,10 +472,12 @@ class BaseModel(metaclass=_model_construction.ModelMetaclass):
fields_values: dict[str, Any] = {}
defaults: dict[str, Any] = {} # keeping this separate from `fields_values` helps us compute `_fields_set`
for name, field in cls.model_fields.items():
- if field.alias and field.alias in values:
- fields_values[name] = values.pop(field.alias)
- elif name in values:
- fields_values[name] = values.pop(name)
+ value_name = field.alias if field.alias else name
+ if value_name in values:
+ value = values.pop(value_name)
+ if field.annotation and issubclass(field.annotation, BaseModel):
+ value = field.annotation.model_construct(**value)
+ fields_values[name] = value
elif not field.is_required():
defaults[name] = field.get_default(call_default_factory=True)
if _fields_set is None: I guess, some edge cases could exist and they are always makes it harder 🤷🏻 |
Checks
Bug
I have built a "nested" Basemodel (e.g, the fields of a basemodel are basemodels themselves), where I have validation that warns in certain cases, and validation that sets some attributes on other cases. I would like to be able to pass this validated model to a very similar BaseModel, without warnings and setting occurring again.
I looked at
BaseModel.construct
, which is advertised as exactly what I want, but it looks like none of its fields are set to be baseclasses themselves. Is this intentional behaviour? This does not occur if I useBaseModel.parse_obj
.If this is intentional, is there any way I instantiate a nested model without validation?
To be extra clear with the example below: Given a dict
data
, I would like to create objecta
without validation occuring.Output of
python -c "import pydantic.utils; print(pydantic.utils.version_info())"
:The text was updated successfully, but these errors were encountered: