当many=True时,正在验证数据列表



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

class Human(models.Model):
name = models.TextField(unique=True)
class HumanSer(serializers.ModelSerializer):
class Meta:
model = Human
fields = '__all__'

我想验证一下,当给出一个名称列表时,该列表中的名称不会重复,而不会影响数据库(下文将对此进行详细介绍(。

data = [{'name': 'John}, {'name': 'John'}]
ser = HumanSer(data=data, many=True)

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

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

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

如果您只关心输入列表中的唯一项,请查看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')]}

但如果你想在整个数据库中验证唯一性,可以看看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__'

(我不确定这种方法的性能(

更新:正如Iain Shelvington所指出的,它可能需要将ListSerializer和UniqueValidator解决方案结合起来,这是一个悬而未决的问题。

最新更新