Рамка 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

Хорошо, это довольно глупо, и очень маловероятно, чтобы кто-то, кроме меня, допустил эту ошибку, но я поместил ту же модель в два класса сериализаторов, вследствие чего у меня была эта проблема

Надеюсь, что моя ошибка поможет кому-то!