Unique validation on nested serializer on Django Rest Framework

后端 未结 3 2261
天涯浪人
天涯浪人 2020-12-03 11:09

I have a case like this, where you have a custom nested serializer relation with a unique field. Sample case:

class GenreSerializer(serializers.ModelSerializ         


        
相关标签:
3条回答
  • 2020-12-03 11:13

    Together than remove the UniqueValidator using

    'name': {'validators': []}
    

    You need to validate the Unique entry yourself ignoring the current object, for not get an 500 error when another person try to save the same name, something like this will work:

        def validate_name(self, value):
            check_query = Genre.objects.filter(name=value)
            if self.instance:
                check_query = check_query.exclude(pk=self.instance.pk)
    
            if self.parent is not None and self.parent.instance is not None:
                genre = getattr(self.parent.instance, self.field_name)
                check_query = check_query.exclude(pk=genre.pk)
    
            if check_query.exists():
                raise serializers.ValidationError('A Genre with this name already exists
    .')
            return value
    

    A method validate_<field> is called for validate all your fields, see the docs.

    0 讨论(0)
  • 2020-12-03 11:24

    You should drop the unique validator for the nested serializer:

    class GenreSerializer(serializers.ModelSerializer):
    
        class Meta:
            fields = ('name',) #This field is unique
            model = Genre
            extra_kwargs = {
                'name': {'validators': []},
            }
    

    You may want to print your serializer before to make sure you don't have other validators on that field. If you have some, you'll have to include them in the list.

    Edit: If you need to ensure the uniqueness constraint for creation, you should do it in the view after the serializer.is_valid has been called and before serializer.save.

    0 讨论(0)
  • 2020-12-03 11:24

    This happens because the nested serializer (GenreSerializer) needs an instance of the object to validate the unique constraint correctly (like put a exclude clause to the queryset used on validation) and by default, a serializer will not pass the instance of related objects to fileds the are nested serializers when runs the to_internal_value() method. See here

    Another way to solve this problem is override the get_fields() method on parent serializer and pass the instance of related object

    class BookSerializer(serializers.ModelSerializer):
    
        def get_fields(self):
            fields = super(BookSerializer, self).get_fields()
            try: # Handle DoesNotExist exceptions (you may need it)
                if self.instance and self.instance.genre:
                    fields['genre'].instance = self.instance.genre
            except Genre.DoesNotExist:
                pass
            return fields
    
    0 讨论(0)
提交回复
热议问题