抑制 Django REST 框架中的 "field should be unique" 错误
Suppress "field should be unique" error in Django REST framework
我有一个像这样的模型
class MyModel(models.Model):
uuid = models.CharField(max_length=40, unique=True)
和一个序列化程序
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('uuid')
我想接收带有 MyModel 对象的 JSON,但它可以是现有对象。因此,当我将 serializer.is_valid()
与有关现有对象的数据一起使用时,它会给我一个错误:
for record in request['records']:
# request - body of JSON request,
# 'records' - array of records I want to add or update
serializer = MyModelSerializer(data=record)
if serializer.is_valid():
# Do stuff
serializer.save()
错误:
{"uuid":["This field must be unique."]}
有没有办法区分新对象和现有对象的行为?特别是,我想创建新的 MyModel
对象(如果它还不是数据库)并更新现有的 MyModel
对象(如果它存在)。
您基本上是在通过尝试使用 POST 请求创建新实例和更新现有实例来重载 REST API 的单个入口点。此外,您似乎正试图在 单个 POST 请求中同时创建和更新多个实例。
Django REST Framework (DRF) 期望 POST 请求仅创建新实例。因此,发送现有实例记录会触发 uuid
字段的唯一约束冲突,因为 DRF 会尝试将该记录创建为新实例,因为现有实例已经具有该 uuid 值。
使您的 REST API 更多 "RESTful" 的解决方案是将记录的创建和更新分别分为 POST 和 PUT 请求。目前还不清楚你是否使用generic API views provided by DRF,但你可以使用CreateAPIView
到POST新实例,然后创建一个单独的UpdateAPIView
到PUT and/or PATCH现有实例。更好的是,您可以使用通用视图 ListCreateAPIView
和 RetrieveUpdateAPIView
.
通过 GET 对这两个端点进行检索
最后,为了处理批量请求(即单个请求中的多个实例),您可以覆盖内置视图方法或使用第 3 方包,例如 django-rest-framework-bulk.
我有一个情况,我有一个深层创建方法,在端点之上有 2 层层次结构,所有模型都是幂等的很重要。
我覆盖了序列化程序中的验证,并手动创建了它。
将字段添加到顶部的 class 很重要(否则验证器将不会 运行)
class ParticipantSerializer(serializers.HyperlinkedModelSerializer):
device = DeviceSerializer(required=False)
uuid = serializers.CharField()
def validate_uuid(self, value):
if value is not None and isinstance(value, basestring) and len(value) < 256:
return value
else:
if value is not None:
raise serializers.ValidationError("UUID can't be none")
elif isinstance(value, basestring):
raise serializers.ValidationError("UUID must be a string")
elif len(value) < 256:
raise serializers.ValidationError("UUID must be below 256 characters")
else:
raise serializers.ValidationError("UUID has failed validation")
class Meta:
model = Participant
fields = ("uuid", "platform", "device")
我有一个像这样的模型
class MyModel(models.Model):
uuid = models.CharField(max_length=40, unique=True)
和一个序列化程序
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('uuid')
我想接收带有 MyModel 对象的 JSON,但它可以是现有对象。因此,当我将 serializer.is_valid()
与有关现有对象的数据一起使用时,它会给我一个错误:
for record in request['records']:
# request - body of JSON request,
# 'records' - array of records I want to add or update
serializer = MyModelSerializer(data=record)
if serializer.is_valid():
# Do stuff
serializer.save()
错误:
{"uuid":["This field must be unique."]}
有没有办法区分新对象和现有对象的行为?特别是,我想创建新的 MyModel
对象(如果它还不是数据库)并更新现有的 MyModel
对象(如果它存在)。
您基本上是在通过尝试使用 POST 请求创建新实例和更新现有实例来重载 REST API 的单个入口点。此外,您似乎正试图在 单个 POST 请求中同时创建和更新多个实例。
Django REST Framework (DRF) 期望 POST 请求仅创建新实例。因此,发送现有实例记录会触发 uuid
字段的唯一约束冲突,因为 DRF 会尝试将该记录创建为新实例,因为现有实例已经具有该 uuid 值。
使您的 REST API 更多 "RESTful" 的解决方案是将记录的创建和更新分别分为 POST 和 PUT 请求。目前还不清楚你是否使用generic API views provided by DRF,但你可以使用CreateAPIView
到POST新实例,然后创建一个单独的UpdateAPIView
到PUT and/or PATCH现有实例。更好的是,您可以使用通用视图 ListCreateAPIView
和 RetrieveUpdateAPIView
.
最后,为了处理批量请求(即单个请求中的多个实例),您可以覆盖内置视图方法或使用第 3 方包,例如 django-rest-framework-bulk.
我有一个情况,我有一个深层创建方法,在端点之上有 2 层层次结构,所有模型都是幂等的很重要。
我覆盖了序列化程序中的验证,并手动创建了它。
将字段添加到顶部的 class 很重要(否则验证器将不会 运行)
class ParticipantSerializer(serializers.HyperlinkedModelSerializer):
device = DeviceSerializer(required=False)
uuid = serializers.CharField()
def validate_uuid(self, value):
if value is not None and isinstance(value, basestring) and len(value) < 256:
return value
else:
if value is not None:
raise serializers.ValidationError("UUID can't be none")
elif isinstance(value, basestring):
raise serializers.ValidationError("UUID must be a string")
elif len(value) < 256:
raise serializers.ValidationError("UUID must be below 256 characters")
else:
raise serializers.ValidationError("UUID has failed validation")
class Meta:
model = Participant
fields = ("uuid", "platform", "device")