簡體   English   中英

關於Django Rest Framework上嵌套序列化器的唯一驗證

[英]Unique validation on nested serializer on Django Rest Framework

我有這樣的情況,你有一個自定義嵌套序列化器關系與唯一字段。 樣例:

class GenreSerializer(serializers.ModelSerializer):

    class Meta:
        fields = ('name',) #This field is unique
        model = Genre

class BookSerializer(serializers.ModelSerializer):

    genre = GenreSerializer()

    class Meta:
        model = Book
        fields = ('name', 'genre')

    def create(self, validated_data):
        genre = validated_data.pop('genre')
        genre = Genre.objects.get(**genre)
        return Book.objects.create(genre=genre, **validated_data)

問題:當我嘗試保存json對象如{“name”:“The Prince”,“genre”:{“name”:“History”}} DRF嘗試驗證流派對象的唯一約束以及“History” exists拋出一個例外,因為一個名為“History”的類型必須是唯一的,這是真的,但我只是試圖關聯對象而不是一起創建。

非常感謝!!

您應該刪除嵌套序列化程序的唯一驗證器:

class GenreSerializer(serializers.ModelSerializer):

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

您可能需要先打印序列化程序,以確保該字段上沒有其他驗證器。 如果你有一些,你必須將它們包括在列表中。

編輯:如果您需要確保創造的唯一性約束,你應該這樣做在視圖中后serializer.is_valid已經調用了前serializer.save

發生這種情況是因為嵌套的序列化程序( GenreSerializer )需要對象的實例來正確驗證唯一約束(例如將exclude子句放到驗證時使用的查詢集),並且默認情況下,序列化程序不會將相關對象的實例傳遞給fileds運行to_internal_value()方法時是嵌套的序列化程序。 看到這里

解決此問題的另一種方法是覆蓋父序列化器上的get_fields()方法並傳遞相關對象的實例

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

一起比使用刪除UniqueValidator

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

您需要自己忽略當前對象來驗證Unique條目,因為當另一個人嘗試保存相同名稱時不會出現500錯誤,這樣的事情會起作用:

    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

調用方法validate_<field>以驗證所有字段,請參閱文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM