Skip to content

Allow run_validators() to handle non-dict types. #6365

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

Merged
merged 1 commit into from
Jan 8, 2019

Conversation

carltongibson
Copy link
Collaborator

@carltongibson carltongibson commented Dec 19, 2018

Fixes #6053.

to_internal_value() is expected to return a dict. #5922 relied on this, but users are implementing custom serialisers that return application objects[*]. This PR bypasses the read-only defaults handling for non-dict objects.

[*]: This is why static typing will never work for Python 😀

Original test case thanks to @vdel in #6242.

@carltongibson carltongibson added this to the 3.9.1 Release milestone Dec 19, 2018
@carltongibson carltongibson changed the title All run_validators() to handle non-dict types. Allow run_validators() to handle non-dict types. Dec 19, 2018
Fixes encode#6053.

Original test case thanks to Vincent Delaitre in encode#6242.
@tomchristie
Copy link
Member

tomchristie commented Jan 8, 2019

Huffs grumpily OKAY FINE

Seriously tho, yeah cool. Probably makes sense given the feedback on that ticket. Thanks fella.

@tomchristie tomchristie merged commit 587058e into encode:master Jan 8, 2019
@carltongibson carltongibson deleted the 391/fix-6053 branch March 3, 2019 19:19
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.
@kai-nashi
Copy link

kai-nashi commented Aug 26, 2024

@carltongibson Can you remind, why we only for dict use not the origin object but copy created by adding data to read only defaults?

def run_validators(self, value):
"""
Add read_only fields with defaults to value before running validators.
"""
if isinstance(value, dict):
to_validate = self._read_only_defaults()
to_validate.update(value)
else:
to_validate = value
super().run_validators(to_validate)

@carltongibson
Copy link
Collaborator Author

@kai-nashi When a field has a default value, it needs to be part of the serialiser data, even when otherwise read-only.

def test_read_only_fields_with_default(self):
"""
Special case of read_only + default DOES validate unique_together.
"""
class ReadOnlyFieldWithDefaultSerializer(serializers.ModelSerializer):
race_name = serializers.CharField(max_length=100, read_only=True, default='example')
class Meta:
model = UniquenessTogetherModel
fields = ('id', 'race_name', 'position')
data = {'position': 2}
serializer = ReadOnlyFieldWithDefaultSerializer(data=data)
assert len(serializer.validators) == 1
assert isinstance(serializer.validators[0], UniqueTogetherValidator)
assert serializer.validators[0].fields == ('race_name', 'position')
assert not serializer.is_valid()
assert serializer.errors == {
'non_field_errors': [
'The fields race_name, position must make a unique set.'
]
}

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.

Returning an object in Serializer.to_internal_value is not working any more since 3.8.2
4 participants