Skip to content

Commit 42eb5a4

Browse files
Fix read_only + default unique_together validation. (#5922)
* Add test for read_only + default unique_together validation. * Fix read_only + default validation
1 parent 32caca4 commit 42eb5a4

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

rest_framework/serializers.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,30 @@ def run_validation(self, data=empty):
441441

442442
return value
443443

444+
def _read_only_defaults(self):
445+
fields = [
446+
field for field in self.fields.values()
447+
if (field.read_only) and (field.default != empty) and (field.source != '*') and ('.' not in field.source)
448+
]
449+
450+
defaults = OrderedDict()
451+
for field in fields:
452+
try:
453+
default = field.get_default()
454+
except SkipField:
455+
continue
456+
defaults[field.field_name] = default
457+
458+
return defaults
459+
460+
def run_validators(self, value):
461+
"""
462+
Add read_only fields with defaults to value before running validators.
463+
"""
464+
to_validate = self._read_only_defaults()
465+
to_validate.update(value)
466+
super(Serializer, self).run_validators(to_validate)
467+
444468
def to_internal_value(self, data):
445469
"""
446470
Dict of native values <- Dict of primitive datatypes.
@@ -1477,6 +1501,12 @@ def get_unique_together_validators(self):
14771501
if (field.source != '*') and ('.' not in field.source)
14781502
}
14791503

1504+
# Special Case: Add read_only fields with defaults.
1505+
field_names |= {
1506+
field.source for field in self.fields.values()
1507+
if (field.read_only) and (field.default != empty) and (field.source != '*') and ('.' not in field.source)
1508+
}
1509+
14801510
# Note that we make sure to check `unique_together` both on the
14811511
# base model class, but also on any parent classes.
14821512
validators = []

tests/test_validators.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,30 @@ class Meta:
277277
""")
278278
assert repr(serializer) == expected
279279

280+
def test_read_only_fields_with_default(self):
281+
"""
282+
Special case of read_only + default DOES validate unique_together.
283+
"""
284+
class ReadOnlyFieldWithDefaultSerializer(serializers.ModelSerializer):
285+
race_name = serializers.CharField(max_length=100, read_only=True, default='example')
286+
287+
class Meta:
288+
model = UniquenessTogetherModel
289+
fields = ('id', 'race_name', 'position')
290+
291+
data = {'position': 2}
292+
serializer = ReadOnlyFieldWithDefaultSerializer(data=data)
293+
294+
assert len(serializer.validators) == 1
295+
assert isinstance(serializer.validators[0], UniqueTogetherValidator)
296+
assert serializer.validators[0].fields == ('race_name', 'position')
297+
assert not serializer.is_valid()
298+
assert serializer.errors == {
299+
'non_field_errors': [
300+
'The fields race_name, position must make a unique set.'
301+
]
302+
}
303+
280304
def test_allow_explict_override(self):
281305
"""
282306
Ensure validators can be explicitly removed..

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy