当 Many=True 时验证数据列表

Dav*_* R. 6 django django-rest-framework

假设给出以下模型和序列化器。

class Human(models.Model):
    name = models.TextField(unique=True)

class HumanSer(serializers.ModelSerializer):
    class Meta:
        model = Human
        fields = '__all__'
Run Code Online (Sandbox Code Playgroud)

我想验证一下,当给出一个名称列表时,该列表中的名称不会重复,而无需访问数据库(更多内容见下文)。

data = [{'name': 'John}, {'name': 'John'}]
ser = HumanSer(data=data, many=True)
Run Code Online (Sandbox Code Playgroud)

在完美的世界中,我会添加validate_name方法,访问所有先前验证的条目,并引发“ValidationError”。

目前这似乎不可能,所以我找到的选项是:

  1. 访问.initial_data并进行比较。这似乎不太可靠,因为我必须小心,因为我正在处理未经验证的原始数据;注意数据是否是列表等。
  2. 什么都不做,在这种情况下.is_valid()返回True,但.save()抛出异常。在这种情况下,REST 调用整体失败,我无法指出名称重复的用户。

ujl*_*bu4 2

如果您只关心输入列表中的唯一项目,请查看ListSerializer

class HumanListSerializer(serializers.ListSerializer):

    def validate(self, data):
        validation_set = set()

        for item in data:
            if item["name"] in validation_set:
                raise serializers.ValidationError(f"duplicated item: {item['name']}")
            else:
                validation_set.add(item["name"])

        return data


class HumanSerializer(serializers.Serializer):
    name = serializers.CharField()

    class Meta:
        list_serializer_class = HumanListSerializer


if __name__ == '__main__':
    data = [{'name': 'John', "xxx": "xz"}, {'name': 'John'}]
    ser = HumanSerializer(data=data, many=True)
    print(f"is valid: {ser.is_valid()}")
    print(f"errors: {ser.errors}")

# >>> is valid: False
# >>> errors: {'non_field_errors': [ErrorDetail(string='duplicated item: John', code='invalid')]}

Run Code Online (Sandbox Code Playgroud)

但是如果你想验证整个数据库的唯一性,请看一下UniqueValidator

from rest_framework.validators import UniqueValidator

class HumanSer(serializers.ModelSerializer):
    name = serializers.CharField(
        validators=[UniqueValidator(queryset=Human.objects.all())]
    )

    class Meta:
        model = Human
        fields = '__all__'
Run Code Online (Sandbox Code Playgroud)

我不确定这种方法的性能

更新:正如 Iain Shelvington 指出的那样,存在一个悬而未决的问题,其中可能需要结合 ListSerializer 和 UniqueValidator 解决方案。