Чтобы проиллюстрировать мою проблему, скажем, у меня есть простая 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:
Но если я POST, PUT или PATCH так, что я нарушаю объект -уровень правила проверки, среда REST Django не перехватывает исключение, и сервер аварийно завершает работу и отображает трассировку, подобную этой:
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 прекрасно обработает исключение:
Вот (наконец-то ;-) мои вопросы:
Почему я должен выполнить проверку на уровне объекта в оба модель и сериализатор, когда мне нужно только выполнить проверку на уровне поля в модели, и сериализатор будет нормально обрабатывать исключения?
Так должен работать Django REST Framework?Похоже, что сериализатор должен уметь обрабатывать все ValidationError
s, поднятые моделью.