vitalik / django-ninja

💨 Fast, Async-ready, Openapi, type hints based framework for building APIs
https://django-ninja.dev
MIT License
7.24k stars 430 forks source link

[BUG] If validate assignment is true, the value will not change. #1223

Closed milksys closed 3 months ago

milksys commented 4 months ago

If validate assignment is true, the value will not change.

this is sampel code

Describe the bug

from ninja import Schema

class Model(Schema):
    name: str
    is_bool: bool

    model_config = ConfigDict(validate_assignment=True)

model = Model(name="NewJeans",  is_bool=False)

print(model)  # => name="NewJeans" is_bool=False

model.name= "Ive"
model.is_bool = True

# Not change value
print(model)  # => name="NewJeans" is_bool=False

In the previous 1.1.0 version, that PR threw an error, but now the value does not change (https://github.com/vitalik/django-ninja/pull/1024)

Versions (please complete the following information):

austinpgraham commented 4 months ago

I've been debugging this over the past couple of hours, and seems to be related how pydantic updates fields after they've been validated; appears pydantic-core is updating the dict property directly: https://github.com/pydantic/pydantic-core/blob/0e6b377d2bef52e744deff22314269c8751f7b00/src/validators/dataclass.rs#L368 (I'm not super familiar with the pydantic codebase so I may be looking at the wrong place)

However, I did validate this by debugging through the existing test added in the PR you linked @milksys.

tests/test_schema.py 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /Users/me/django-ninja/ninja/schema.py(225)_run_root_validator()
-> return handler(values)
(Pdb) c

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB continue (IO-capturing resumed) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /Users/me/django-ninja/tests/test_schema.py(212)test_django_getter_validates_assignment_and_reassigns_the_value()
-> schema_inst.str_var = "reassigned_value"
(Pdb) c

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB continue (IO-capturing resumed) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /Users/me/django-ninja/ninja/schema.py(225)_run_root_validator()
-> return handler(values)
(Pdb) handler(values)
<DjangoGetter: ValidateAssignmentSchema(str_var='test_value')>
(Pdb) handler(values).__dict__
{'str_var': 'reassigned_value', '__pydantic_extra__': None}
(Pdb) 

Looks like the dict of the DjangoGetter is getting updated directly, rather than the _obj, which is the representation of the actual object being validated. I don't have a good solution yet, will try and tackle it this weekend unless someone else gets to it first.

austinpgraham commented 4 months ago

@milksys PR is out: https://github.com/vitalik/django-ninja/pull/1232