Django Rest Framework自动处理哪些类型的验证?

时间:2018-11-07 21:48:39

标签: django django-rest-framework django-serializer

可以说我有一个定义如下的模型:

from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator

alphanumeric_validator = RegexValidator(r'^[a-zA-Z0-9]*$', 'Only alphanumeric characters are allowed.')

class Person(model.Model):
    name = models.CharField(max_length=60, validators=[alphanumeric_validator])
    number = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100)])
    email = models.EmailField()

现在,可以说我正在使用Django Rest Framework序列化和创建Person对象。看起来像这样:

from rest_framework import serializers
from .models import Person
from rest_framework.response import Response

class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = ('name', 'number', 'email')

class PostPerson(APIView):
    def post(self, request, format=None):
        serializer = PersonSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()=
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

现在,我的问题是:当我使用is_valid()验证序列化程序时,DRF是否处理validators=[alphanumeric_validator]validators=[MinValueValidator(0), MaxValueValidator(100)]?另外,我确定DRF会自动处理max_length属性,但是它还会使用正确的正则表达式检查email是否是实际的电子邮件地址吗?

我通常对clean,full_clean以及在表单验证和序列化程序验证期间调用的所有方法感到困惑,因此想获得一些扎实的解释。

谢谢。

1 个答案:

答案 0 :(得分:2)

Django rest框架验证的行为类似于Django ModelForm验证;它会从您的模型字段中获取参数并进行相应的验证。

例如,我们将使用一个简单的模型和序列化器类,该类的字段具有唯一性约束。

class CustomerReportRecord(models.Model):
    time_raised = models.DateTimeField(default=timezone.now, editable=False)
    reference = models.CharField(unique=True, max_length=20)


class CustomerReportSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomerReportRecord

打开Django shell时,我们可以看到验证器已应用于序列化程序(注意max_lengthvalidators列表)

>>> from project.example.serializers import CustomerReportSerializer
>>> serializer = CustomerReportSerializer()
>>> print(repr(serializer))
CustomerReportSerializer():
    id = IntegerField(label='ID', read_only=True)
    time_raised = DateTimeField(read_only=True)
    reference = CharField(max_length=20, validators=[<UniqueValidator(queryset=CustomerReportRecord.objects.all())>])

打印序列化程序实例的repr将向您确切显示它适用的验证规则。在模型实例上没有额外的隐藏验证行为。

涉及.clean.full_clean方法时,这是验证用户输入数据的另一种方法-将其标准化为一致的格式。当您在表单上而不是在其余框架序列化程序中调用.is_valid()方法时,它们将以Django形式执行。

但是回到REST框架验证器。让我们看一下Serializer.to_internal_value方法。

def to_internal_value(self, data):
    """
    Dict of native values <- Dict of primitive datatypes.
    """
    if not isinstance(data, dict):
        message = self.error_messages['invalid'].format(
            datatype=type(data).__name__
        )
        raise ValidationError({
            api_settings.NON_FIELD_ERRORS_KEY: [message]
        })

    ret = OrderedDict()
    errors = OrderedDict()
    fields = self._writable_fields

    for field in fields:
        validate_method = getattr(self, 'validate_' + field.field_name, None)
        primitive_value = field.get_value(data)
        try:
            validated_value = field.run_validation(primitive_value)
            if validate_method is not None:
                validated_value = validate_method(validated_value)
        except ValidationError as exc:
            errors[field.field_name] = exc.detail
        except DjangoValidationError as exc:
            errors[field.field_name] = list(exc.messages)
        except SkipField:
            pass
        else:
            set_value(ret, field.source_attrs, validated_value)

    if errors:
        raise ValidationError(errors)

    return ret

我们在这里可以看到串行器调用field.run_validation方法,该方法使用模型字段验证器,如果验证失败,它们将引发DjangoValidationError。如果成功,它将继续运行存在的所有其他验证器,例如序列化程序字段特定的验证器(.validate_<field_name>)。

在此处详细了解验证及其在Django和DRF中的工作原理:

  1. Form Field Validation Django 2.1
  2. Validators - DRF Docs
  3. Serializer Validation - DRF Docs
  4. Correct way to validate Django Models
  5. DRF Serializer code

希望这可以帮助您理解验证在DRF中的工作原理,即使只是一点点

编辑:只要您要在其中存储电子邮件的字段在模型中定义为EmailField,DRF就会验证电子邮件。有关更多信息,请参见here