Skip to content

Commit 8de6a6c

Browse files
committed
fix(blank/unique): add default handling for blank=True field
Signed-off-by: Sergei Shishov <[email protected]>
1 parent a7d050f commit 8de6a6c

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

rest_framework/serializers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,8 @@ def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs
14961496
default = unique_constraint_field.default
14971497
elif unique_constraint_field.null:
14981498
default = None
1499+
elif unique_constraint_field.blank:
1500+
default = ''
14991501
else:
15001502
default = empty
15011503

tests/test_validators.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ class Meta:
149149
unique_together = ('race_name', 'position')
150150

151151

152+
class BlankUniquenessTogetherModel(models.Model):
153+
race_name = models.CharField(max_length=100, blank=True)
154+
position = models.IntegerField()
155+
156+
class Meta:
157+
unique_together = ('race_name', 'position')
158+
159+
152160
class NullUniquenessTogetherModel(models.Model):
153161
"""
154162
Used to ensure that null values are not included when checking
@@ -176,6 +184,12 @@ class Meta:
176184
fields = '__all__'
177185

178186

187+
class BlankUniquenessTogetherSerializer(serializers.ModelSerializer):
188+
class Meta:
189+
model = BlankUniquenessTogetherModel
190+
fields = '__all__'
191+
192+
179193
class NullUniquenessTogetherSerializer(serializers.ModelSerializer):
180194
class Meta:
181195
model = NullUniquenessTogetherModel
@@ -461,6 +475,34 @@ def test_do_not_ignore_validation_for_null_fields(self):
461475
serializer = NullUniquenessTogetherSerializer(data=data)
462476
assert not serializer.is_valid()
463477

478+
def test_validation_for_provided_blank_fields(self):
479+
BlankUniquenessTogetherModel.objects.create(
480+
position=1
481+
)
482+
data = {
483+
'race_name': '',
484+
'position': 1
485+
}
486+
serializer = BlankUniquenessTogetherSerializer(data=data)
487+
assert not serializer.is_valid()
488+
489+
def test_validation_for_missing_blank_fields(self):
490+
BlankUniquenessTogetherModel.objects.create(
491+
position=1
492+
)
493+
data = {
494+
'position': 1
495+
}
496+
serializer = BlankUniquenessTogetherSerializer(data=data)
497+
assert not serializer.is_valid()
498+
499+
def test_ignore_validation_for_missing_blank_fields(self):
500+
data = {
501+
'position': 1
502+
}
503+
serializer = BlankUniquenessTogetherSerializer(data=data)
504+
assert serializer.is_valid(), serializer.errors
505+
464506
def test_ignore_validation_for_unchanged_fields(self):
465507
"""
466508
If all fields in the unique together constraint are unchanged,
@@ -589,6 +631,18 @@ class Meta:
589631
]
590632

591633

634+
class UniqueConstraintBlankModel(models.Model):
635+
title = models.CharField(max_length=100, blank=True)
636+
age = models.IntegerField()
637+
tag = models.CharField(max_length=100, blank=True)
638+
639+
class Meta:
640+
constraints = [
641+
# Unique constraint on 2 blank fields
642+
models.UniqueConstraint(name='unique_constraint', fields=('age', 'tag'), condition=~models.Q(models.Q(title='') & models.Q(tag='True')))
643+
]
644+
645+
592646
class UniqueConstraintNullableModel(models.Model):
593647
title = models.CharField(max_length=100)
594648
age = models.IntegerField(null=True)
@@ -607,6 +661,12 @@ class Meta:
607661
fields = '__all__'
608662

609663

664+
class UniqueConstraintBlankSerializer(serializers.ModelSerializer):
665+
class Meta:
666+
model = UniqueConstraintBlankModel
667+
fields = ('title', 'age', 'tag')
668+
669+
610670
class UniqueConstraintNullableSerializer(serializers.ModelSerializer):
611671
class Meta:
612672
model = UniqueConstraintNullableModel
@@ -714,6 +774,12 @@ def test_single_field_uniq_validators(self):
714774
ids_in_qs = {frozenset(v.queryset.values_list(flat=True)) for v in validators if hasattr(v, "queryset")}
715775
assert ids_in_qs == {frozenset([1]), frozenset([3])}
716776

777+
def test_blank_uqnique_constraint_fields_are_not_required(self):
778+
serializer = UniqueConstraintBlankSerializer(data={'age': 25})
779+
self.assertTrue(serializer.is_valid(), serializer.errors)
780+
result = serializer.save()
781+
self.assertIsInstance(result, UniqueConstraintBlankModel)
782+
717783
def test_nullable_unique_constraint_fields_are_not_required(self):
718784
serializer = UniqueConstraintNullableSerializer(data={'title': 'Bob'})
719785
self.assertTrue(serializer.is_valid(), serializer.errors)

0 commit comments

Comments
 (0)