【问题标题】:What types of validations are automatically handled by Django Rest Framework?Django Rest Framework 自动处理哪些类型的验证?
【发布时间】:2019-04-11 09:47:24
【问题描述】:

假设我有一个定义如下的模型:

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 以及在表单验证和序列化器验证期间调用的所有方法感到困惑,因此希望得到一些可靠的解释。

提前致谢。

【问题讨论】:

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


    【解决方案1】:

    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 方法时,这只是验证用户输入数据的另一种方法——将其规范化为一致的格式。当您在 form 上调用 .is_valid() 方法时,这些将在 Django 表单中执行,而不是在您的 rest 框架序列化程序中。

    回到 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_&lt;field_name&gt;)。

    在此处阅读有关验证及其在 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

    【讨论】:

      猜你喜欢
      • 2015-12-10
      • 1970-01-01
      • 2015-03-17
      • 2015-12-26
      • 2015-09-25
      • 1970-01-01
      • 2015-12-16
      • 2019-11-20
      • 1970-01-01
      相关资源
      最近更新 更多