В Django REST Framework, почему сериализаторы правильно обрабатывают исключения проверки на уровне поля в моделях, а не проверку на уровне объекта? - PullRequest
0 голосов
/ 01 декабря 2018

Чтобы проиллюстрировать мою проблему, скажем, у меня есть простая Person модель, определенная следующим образом:

from django.db import models
from django.core.validators import MinLengthValidator, MaxLengthValidator, ValidationError

class Person(models.Model):
    first_name = models.CharField(max_length=100, null=False, blank=False,
                                  validators=[MinLengthValidator(limit_value=1),
                                              MaxLengthValidator(limit_value=100)])
    last_name = models.CharField(max_length=100, null=True, blank=True,
                                 validators=[MinLengthValidator(limit_value=1),
                                             MaxLengthValidator(limit_value=100)])

    def clean(self):
        self.validate()
        super().clean()

    def save(self, *args, **kwargs):
        self.full_clean()
        super().save(*args, **kwargs)

    def validate(self):
        """The first and last names cannot be the same strings."""
        if (self.first_name and self.last_name and
                self.first_name.lower() == self.last_name.lower()):
            raise ValidationError('First and last names, if both are provided, cannot be the same.',
                                  code='invalid',
                                  params={'first_name': self.first_name,
                                          'last_name': self.last_name})
  • Обратите внимание, что оба поля first_name и last_name имеют уровень поля проверка, связанная с ними.(Моя база данных разработчика - SQLite, и она не выполняет проверку длины. Поэтому мне пришлось добавить validators. Но это не мой вопрос.)

Я определил два простых APIView на основеклассы:

from rest_framework import generics
from ..models import Person
from ..serializers import PersonSerializer

class PersonDetailView(generics.RetrieveUpdateDestroyAPIView):
    name = 'person-detail'
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    lookup_field = 'id'

class PersonListView(generics.ListCreateAPIView):
    name = 'person-list'
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    lookup_field = 'id'

Я определил сериализатор на основе Django REST Framework ModelSerializer:

from rest_framework import serializers
from ..models import Person

class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = ('id', 'first_name', 'last_name')

И я сопоставил несколько URL-адресов.

Если я POST,PUT или PATCH, так что я нарушаю правила проверки на уровне поля (например, я пытаюсь передать имя длиной 101 символ), Django REST Framework перехватывает исключение из класса модели и отображает егосоответственно.Вот как это выглядит в браузере API:

enter image description here

Но если я POST, PUT или PATCH так, что я нарушаю объект -уровень правила проверки, среда REST Django не перехватывает исключение, и сервер аварийно завершает работу и отображает трассировку, подобную этой:

enter image description here

MyРешение состояло в том, чтобы добавить валидацию на уровне объекта к сериализатору, а также к модели.Вот сериализатор с его собственным validate методом:

from rest_framework import serializers
from rest_framework.validators import ValidationError

from ..models import Person

class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = ('id', 'first_name', 'last_name')

    def validate(self, attrs):
        first_name = attrs.get('first_name')
        last_name = attrs.get('last_name')
        if first_name and last_name and first_name.lower() == last_name.lower():
            raise ValidationError('First and last names must be different.',
                                  code='invalid')
        return attrs

Если я сделаю это, тогда Django REST Framework прекрасно обработает исключение:

enter image description here

Вот (наконец-то ;-) мои вопросы:

Почему я должен выполнить проверку на уровне объекта в оба модель и сериализатор, когда мне нужно только выполнить проверку на уровне поля в модели, и сериализатор будет нормально обрабатывать исключения?

Так должен работать Django REST Framework?Похоже, что сериализатор должен уметь обрабатывать все ValidationError s, поднятые моделью.

Ответы [ 2 ]

0 голосов
/ 15 мая 2019

Post DRF 3.0, метод .clean() не будет вызываться как часть проверки сериализатора, как это было бы при использовании ModelForm, прочитайте этот https://www.django -rest-framework.org / community / 3.0-announce/#differences-between-modelserializer-validation-and-modelform.

0 голосов
/ 01 декабря 2018

Это так.Вам нужно поместить метод проверки в сериализатор:

class PersonSerializer(serializer.ModelSerializer):

    def validate_first_name(self, value):
        if len(value)> 100:
            raise serializer.ValidationError("Can't be more than 100")
        return value
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...