在Django REST框架中,为什么序列化程序正确地处理模型中的字段级验证异常,而不是对象级验证?
为了说明我的问题,假设我有一个简单的在Django REST框架中,为什么序列化程序正确地处理模型中的字段级验证异常,而不是对象级验证?,django,validation,django-rest-framework,django-serializer,Django,Validation,Django Rest Framework,Django Serializer,为了说明我的问题,假设我有一个简单的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=
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\u name
字段都具有与之关联的字段级验证。(我的开发数据库是SQLite,它不做长度验证。所以我不得不添加last\u name
验证程序
。但这不是我的问题。)
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框架的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
如果我发布、放置或修补程序违反了字段级验证规则(例如,我尝试提交一个101个字符长的名字),Django REST框架将捕获模型类中的异常并适当地显示它。以下是可浏览API中的外观:
但是,如果我发布、放置或修补程序违反了对象级别验证规则,Django REST framework不会捕获异常,服务器崩溃并显示如下跟踪:
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})
我的解决方案是向序列化程序和模型添加对象级验证。下面是序列化程序及其自己的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框架可以很好地处理异常:
这里(最后;-)是我的问题:
为什么我必须在模型和序列化程序中执行对象级验证,而我只需要在模型中执行字段级验证,并且序列化程序可以很好地处理异常
Django REST框架就是这样运行的吗?似乎序列化程序应该能够优雅地处理模型引发的所有ValidationError
s
是的。您需要在序列化程序中放置一个方法:
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
在DRF 3.0之后,
.clean()
方法不会作为序列化程序验证的一部分被调用,就像使用ModelForm一样,请阅读此文。我很好奇。为什么DRF不能处理对象级的验证规则?方向舵——这正是我的观点。当序列化程序可以很好地处理来自模型的字段级验证异常时,为什么我必须在模型和序列化程序中都有一个验证方法?序列化程序只能处理模型中的对象级验证异常。@SeanFrancisN.Ballais它处理对象级验证:。至于@SteveWehba的观点,嗯,不幸的是drf不能处理django核心验证错误。但它处理restframework.serializer.validationerror。你们仍然可以从模型清理方法中抛出它,不管怎样,它都会起作用。好的,如果您想将这些验证放在模型中并抛出django验证异常,那么您需要将serializer.save()
块放在一个try catch中。这是一个关键的细节-该链接甚至提供了关于如何解决问题的代码