@@ -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+
152160class 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+
179193class 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+
592646class 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+
610670class 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