Skip to content
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

Injection of read-only default values is done too late #6242

Closed
wants to merge 2 commits into from

Conversation

vdel
Copy link

@vdel vdel commented Oct 11, 2018

refs #6053

The value returned by to_internal_value might not be a dictionary. In such cases, when passing the value from this line https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L434 to run_validators just below, it fails to call to_validate.update because value is not a dictionary.

The proposed fix is to inject the default values before converting the input data to internal value

@vdel vdel closed this Oct 11, 2018
@carltongibson
Copy link
Collaborator

Why the close?

@vdel
Copy link
Author

vdel commented Oct 15, 2018

Why the close?

I realized things were more intricated than what I initially thought and I'm not sure to have the time to dig this deeper. Here is my current understanding of the problem:

  1. The to_internal_value here may return an object so we need to inject the default values for read-only before serializing to the internal value.
  2. I guess injecting the read-only defaults directly in the data variable may not be suitable as the later may contain data formatted by an HTML form and we probably want to avoid mixing data in HTML format and more traditional dict/JSON format. Also, to_internal_value does not iterate over the read-only fields.
  3. So I currently "hacked" things by adding a loop on the read-only fields to try to fill the data returned by to_internal_value with the read-only defaults as well. There is probably a nicer way to do so.
  4. This breaks TestReadOnly.test_validate_read_only which checks that read-only fields are not included in validation. With my current solution, the read-only field is now included with its default value and to repair this tests we would need to put assert serializer.validated_data == {'read_only': '789', 'writable': 456} here. I do not think this would be suitable as this data has not been actually validated. (In theory it could be validated though, even if I do not quite see the point ?)

So I have the impression we are a bit stuck in a design issue here:

  • on one side: the validators need the internal data format, which seems to imply we need to embed the default values of read-only fields as well, at least those with defaults?
  • on the other side: we assume that validated_data does not embed read-only fields. I do not know if this a strong DRF assumption and if users of DRF rely on this.

How do you see things?

One solution could maybe be to rename to_internal_value into to_primitive_value, perform validation as done by #5922, and define to_internal_value as a wrapper of validated_data ?

@vdel
Copy link
Author

vdel commented Oct 15, 2018

One solution could maybe be to rename to_internal_value into to_primitive_value, perform validation as done by #5922, and define to_internal_value as a wrapper of validated_data ?

This works but would break the compatibility for everyone who overrides to_internal_data to return a custom python object as the validators are now applied to the dict of primitive values and not an object as before.

I won't have the time to dig deeper than that, hope this helps !

@rpkilby
Copy link
Member

rpkilby commented Oct 15, 2018

I won't have the time to dig deeper than that, hope this helps !

Thanks. I'm sure anyone digging into this will appreciate the legwork you've put into it.

carltongibson added a commit to carltongibson/django-rest-framework that referenced this pull request Dec 19, 2018
Fixes encode#6053.

Original test case thanks to Vincent Delaitre in encode#6242.
@carltongibson
Copy link
Collaborator

Superseded by #6365. Thanks for the effort @vdel!

carltongibson added a commit to carltongibson/django-rest-framework that referenced this pull request Dec 19, 2018
Fixes encode#6053.

Original test case thanks to Vincent Delaitre in encode#6242.
tomchristie pushed a commit that referenced this pull request Jan 8, 2019
Fixes #6053.

Original test case thanks to Vincent Delaitre in #6242.
pchiquet pushed a commit to pchiquet/django-rest-framework that referenced this pull request Nov 17, 2020
Fixes encode#6053.

Original test case thanks to Vincent Delaitre in encode#6242.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants