Рамка Django REST: проверка уникальной_очистки на сериализаторах
Возникли проблемы с возвратом serializer.is_valid()
True
, если экземпляр serializer завершил сбой unique_together
на стороне модели.
Есть ли способ указать в сериализаторе принудительное ограничение unique_together
?
Ответы
Ответ 1
К сожалению, ответ Андреаса не совсем завершен, так как он не будет работать в случае обновления.
Вместо этого вам нужно что-то большее:
def validate(self, attrs):
field1 = attrs.get('field1', self.object.field1)
field2 = attrs.get('field2', self.object.field2)
try:
obj = Model.objects.get(field1=field1, field2=field2)
except StateWithholdingForm.DoesNotExist:
return attrs
if self.object and obj.id == self.object.id:
return attrs
else:
raise serializers.ValidationError('field1 with field2 already exists')
Это будет работать для PUT, PATCH и POST.
Ответ 2
Класс ModelSerializer имеет встроенную функциональность, по крайней мере, в djangorestframework>=3.0.0
, однако, если вы используете serializer
, который не включает все поля, на которые влияет ваш ограничитель unique_together
, тогда вы При сохранении экземпляра, который нарушает его, вы получите IntegrityError
. Например, используя следующую модель:
class Foo(models.Model):
class Meta:
unique_together = ('foo_a', 'foo_b')
a = models.TextField(blank=True)
b = models.TextField(blank=True)
foo_a = models.IntegerField()
foo_b = models.IntegerField(default=2)
и следующий сериализатор и ViewSet:
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = models.Foo
fields = ('a', 'b', 'foo_a')
class FooViewSet(viewsets.ModelViewSet):
queryset = models.Foo.objects.all()
serializer_class = FooSerializer
routes = routers.DefaultRouter()
routes.register(r'foo', FooViewSet)
если вы попытаетесь сохранить два экземпляра с теми же настройками foo_a
и foo_b
, вы получите IntegrityError
. Однако, если мы модифицируем сериализатор следующим образом:
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = models.Foo
fields = ('a', 'b', 'foo_a', 'foo_b')
вы получите правильный код состояния HTTP 400 BAD REQUEST
и соответствующее описательное сообщение JSON в теле ответа:
HTTP 400 BAD REQUEST
Content-Type: application/json
Vary: Accept
Allow: GET, POST, HEAD, OPTIONS
{
"non_field_errors": [
"The fields foo_a, foo_b must make a unique set."
]
}
Я надеюсь, что это поможет вам, даже если это вопрос с несколькими старыми вопросами; -)
Ответ 3
Мне нужно это, чтобы переопределить сообщение по умолчанию. Решил его this.
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
class SomeSerializer(serializers.ModelSerializer):
"""
Demostrating How to Override DRF UniqueTogetherValidator Message
"""
class Meta:
model = Some
validators = [
serializers.UniqueTogetherValidator(
queryset=model.objects.all(),
fields=('field1', 'field2'),
message=_("Some custom message.")
)
]
Similarly you can specify fields
Ответ 4
Да, вы можете сделать это в методе .validate()
сериализатора.
def validate(self, attrs):
try:
Model.objects.get(field1=attrs['field1'], field2=attrs['field2'])
except Model.DoesNotExist:
pass
else:
raise serializers.ValidationError('field1 with field2 already exists')
return attrs
Единственное ограничение, которое вы установили в своей модели, - это создание ограничений базы данных, а не для проверки.
Ответ 5
Имела ту же проблему и из этого ответа fooobar.com/questions/354255/... Мне удалось заставить ее работать, но ей пришлось использовать self.instance
вместо self.object
.
def validate(self, data):
field1 = data.get('field1',None)
field2 = data.get('field2',None)
try:
obj = self.Meta.model.objects.get(field1=field1, field2=field2)
except self.Meta.model.DoesNotExist:
return data
if self.instance and obj.id == self.instance.id:
return data
else:
raise serializers.ValidationError('custom error message')
Ответ 6
Хорошо, это довольно глупо, и очень маловероятно, чтобы кто-то, кроме меня, допустил эту ошибку, но я поместил ту же модель в два класса сериализаторов, вследствие чего у меня была эта проблема
Надеюсь, что моя ошибка поможет кому-то!