mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-12-01 14:04:02 +03:00
Skip validation of NULL field only if it part of unique_together
This commit is contained in:
parent
3d85473edf
commit
fe8d95f93e
|
@ -140,7 +140,10 @@ class UniqueTogetherValidator:
|
||||||
queryset = self.exclude_current_instance(attrs, queryset)
|
queryset = self.exclude_current_instance(attrs, queryset)
|
||||||
|
|
||||||
# Ignore validation if any field is None
|
# Ignore validation if any field is None
|
||||||
if None not in attrs.values() and queryset.exists():
|
checked_values = [
|
||||||
|
value for field, value in attrs.items() if field in self.fields
|
||||||
|
]
|
||||||
|
if None not in checked_values and queryset.exists():
|
||||||
field_names = ', '.join(self.fields)
|
field_names = ', '.join(self.fields)
|
||||||
raise ValidationError(self.message.format(field_names=field_names))
|
raise ValidationError(self.message.format(field_names=field_names))
|
||||||
|
|
||||||
|
|
|
@ -83,11 +83,37 @@ class UniquenessTogetherModel(models.Model):
|
||||||
unique_together = ('race_name', 'position')
|
unique_together = ('race_name', 'position')
|
||||||
|
|
||||||
|
|
||||||
|
class NullUniquenessTogetherModel(models.Model):
|
||||||
|
"""
|
||||||
|
Used to ensure that null values are not included when checking
|
||||||
|
unique_together constraints.
|
||||||
|
|
||||||
|
Ignoring items which have a null in any of the validated fields is the same
|
||||||
|
behavior that database backends will use when they have the
|
||||||
|
unique_together constraint added.
|
||||||
|
|
||||||
|
Example case: a null position could indicate a non-finisher in the race,
|
||||||
|
there could be many non-finishers in a race, but all non-NULL
|
||||||
|
values *should* be unique against the given `race_name`.
|
||||||
|
"""
|
||||||
|
date_of_birth = models.DateField(null=True) # Not part of the uniqueness constraint
|
||||||
|
race_name = models.CharField(max_length=100)
|
||||||
|
position = models.IntegerField(null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ('race_name', 'position')
|
||||||
|
|
||||||
|
|
||||||
class UniquenessTogetherSerializer(serializers.ModelSerializer):
|
class UniquenessTogetherSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = UniquenessTogetherModel
|
model = UniquenessTogetherModel
|
||||||
|
|
||||||
|
|
||||||
|
class NullUniquenessTogetherSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = NullUniquenessTogetherModel
|
||||||
|
|
||||||
|
|
||||||
class TestUniquenessTogetherValidation(TestCase):
|
class TestUniquenessTogetherValidation(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.instance = UniquenessTogetherModel.objects.create(
|
self.instance = UniquenessTogetherModel.objects.create(
|
||||||
|
@ -183,15 +209,33 @@ class TestUniquenessTogetherValidation(TestCase):
|
||||||
assert repr(serializer) == expected
|
assert repr(serializer) == expected
|
||||||
|
|
||||||
def test_ignore_validation_for_null_fields(self):
|
def test_ignore_validation_for_null_fields(self):
|
||||||
UniquenessTogetherModel.objects.create(
|
# None values that are on fields which are part of the uniqueness
|
||||||
race_name=None,
|
# constraint cause the instance to ignore uniqueness validation.
|
||||||
|
NullUniquenessTogetherModel.objects.create(
|
||||||
|
date_of_birth=datetime.date(2000, 1, 1),
|
||||||
|
race_name='Paris Marathon',
|
||||||
position=None
|
position=None
|
||||||
)
|
)
|
||||||
data = {'race_name': None, 'position': None}
|
data = {
|
||||||
serializer = UniquenessTogetherSerializer(data=data)
|
'date': datetime.date(2000, 1, 1),
|
||||||
|
'race_name': 'Paris Marathon',
|
||||||
|
'position': None
|
||||||
|
}
|
||||||
|
serializer = NullUniquenessTogetherSerializer(data=data)
|
||||||
assert serializer.is_valid()
|
assert serializer.is_valid()
|
||||||
|
|
||||||
|
def test_do_not_ignore_validation_for_null_fields(self):
|
||||||
|
# None values that are not on fields part of the uniqueness constraint
|
||||||
|
# do not cause the instance to skip validation.
|
||||||
|
NullUniquenessTogetherModel.objects.create(
|
||||||
|
date_of_birth=datetime.date(2000, 1, 1),
|
||||||
|
race_name='Paris Marathon',
|
||||||
|
position=1
|
||||||
|
)
|
||||||
|
data = {'date': None, 'race_name': 'Paris Marathon', 'position': 1}
|
||||||
|
serializer = NullUniquenessTogetherSerializer(data=data)
|
||||||
|
assert not serializer.is_valid()
|
||||||
|
|
||||||
|
|
||||||
# Tests for `UniqueForDateValidator`
|
# Tests for `UniqueForDateValidator`
|
||||||
# ----------------------------------
|
# ----------------------------------
|
||||||
|
|
Loading…
Reference in New Issue
Block a user