mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 18:08:03 +03:00 
			
		
		
		
	Merge pull request #1459 from linovia/bugfix/optional_unique_validation
Unique constraint are validated even if the field is optional.
This commit is contained in:
		
						commit
						d48e8ca8d6
					
				| 
						 | 
					@ -881,7 +881,7 @@ class ModelSerializer(Serializer):
 | 
				
			||||||
        except KeyError:
 | 
					        except KeyError:
 | 
				
			||||||
            return ModelField(model_field=model_field, **kwargs)
 | 
					            return ModelField(model_field=model_field, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_validation_exclusions(self):
 | 
					    def get_validation_exclusions(self, instance=None):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return a list of field names to exclude from model validation.
 | 
					        Return a list of field names to exclude from model validation.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					@ -893,7 +893,7 @@ class ModelSerializer(Serializer):
 | 
				
			||||||
            field_name = field.source or field_name
 | 
					            field_name = field.source or field_name
 | 
				
			||||||
            if field_name in exclusions \
 | 
					            if field_name in exclusions \
 | 
				
			||||||
                and not field.read_only \
 | 
					                and not field.read_only \
 | 
				
			||||||
                and field.required \
 | 
					                and (field.required or hasattr(instance, field_name)) \
 | 
				
			||||||
                and not isinstance(field, Serializer):
 | 
					                and not isinstance(field, Serializer):
 | 
				
			||||||
                exclusions.remove(field_name)
 | 
					                exclusions.remove(field_name)
 | 
				
			||||||
        return exclusions
 | 
					        return exclusions
 | 
				
			||||||
| 
						 | 
					@ -908,7 +908,7 @@ class ModelSerializer(Serializer):
 | 
				
			||||||
        the full_clean validation checking.
 | 
					        the full_clean validation checking.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            instance.full_clean(exclude=self.get_validation_exclusions())
 | 
					            instance.full_clean(exclude=self.get_validation_exclusions(instance))
 | 
				
			||||||
        except ValidationError as err:
 | 
					        except ValidationError as err:
 | 
				
			||||||
            self._errors = err.message_dict
 | 
					            self._errors = err.message_dict
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,7 +103,7 @@ class BlogPostComment(RESTFrameworkModel):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Album(RESTFrameworkModel):
 | 
					class Album(RESTFrameworkModel):
 | 
				
			||||||
    title = models.CharField(max_length=100, unique=True)
 | 
					    title = models.CharField(max_length=100, unique=True)
 | 
				
			||||||
 | 
					    ref = models.CharField(max_length=10, unique=True, null=True, blank=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Photo(RESTFrameworkModel):
 | 
					class Photo(RESTFrameworkModel):
 | 
				
			||||||
    description = models.TextField()
 | 
					    description = models.TextField()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,7 +161,7 @@ class AlbumsSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Album
 | 
					        model = Album
 | 
				
			||||||
        fields = ['title']  # lists are also valid options
 | 
					        fields = ['title', 'ref']  # lists are also valid options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PositiveIntegerAsChoiceSerializer(serializers.ModelSerializer):
 | 
					class PositiveIntegerAsChoiceSerializer(serializers.ModelSerializer):
 | 
				
			||||||
| 
						 | 
					@ -611,12 +611,15 @@ class ModelValidationTests(TestCase):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Just check if serializers.ModelSerializer handles unique checks via .full_clean()
 | 
					        Just check if serializers.ModelSerializer handles unique checks via .full_clean()
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        serializer = AlbumsSerializer(data={'title': 'a'})
 | 
					        serializer = AlbumsSerializer(data={'title': 'a', 'ref': '1'})
 | 
				
			||||||
        serializer.is_valid()
 | 
					        serializer.is_valid()
 | 
				
			||||||
        serializer.save()
 | 
					        serializer.save()
 | 
				
			||||||
        second_serializer = AlbumsSerializer(data={'title': 'a'})
 | 
					        second_serializer = AlbumsSerializer(data={'title': 'a'})
 | 
				
			||||||
        self.assertFalse(second_serializer.is_valid())
 | 
					        self.assertFalse(second_serializer.is_valid())
 | 
				
			||||||
        self.assertEqual(second_serializer.errors,  {'title': ['Album with this Title already exists.']})
 | 
					        self.assertEqual(second_serializer.errors,  {'title': ['Album with this Title already exists.'],})
 | 
				
			||||||
 | 
					        third_serializer = AlbumsSerializer(data=[{'title': 'b', 'ref': '1'}, {'title': 'c'}])
 | 
				
			||||||
 | 
					        self.assertFalse(third_serializer.is_valid())
 | 
				
			||||||
 | 
					        self.assertEqual(third_serializer.errors,  [{'ref': ['Album with this Ref already exists.']}, {}])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_foreign_key_is_null_with_partial(self):
 | 
					    def test_foreign_key_is_null_with_partial(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user