What types of validations are automatically handled by Django Rest Framework?

£可爱£侵袭症+ 提交于 2019-12-11 06:12:09

问题


Lets say I have a model defined as follows:

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()

Now, lets say I am serializing and creating Person objects using Django Rest Framework. It looks like like this:

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)

Now, my question is this: when I am validating the serializer using is_valid(), does DRF handle the validators=[alphanumeric_validator], and validators=[MinValueValidator(0), MaxValueValidator(100)]? Also, I am sure DRF automatically handles the max_length property, but does it also check if the email is an actual email address using the proper regex?

I am generally just confused about clean, full_clean, and all the methods that are called during form validations and serializer validations, so would like to get some solid explanations.

Thanks in advance.


回答1:


Django rest framework validation behaves similarly to Django ModelForm validation; it takes the arguments from your models fields and validates accordingly.

For example we'll take a simple model & serializer class that has a field with a uniqueness constraint.

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

and when we open up Django shell we can see that the validator has been applied to the serializer (notice the max_length and the validators list)

>>> 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())>])

Printing the repr of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behaviour being called on the model instance.

When it comes to the .clean and .full_clean methods just another way to validate user input data — normalise it to a consistent format. These are executed in Django forms when you call the .is_valid() method on a form, not in your rest framework serializer.

Back to REST framework validators though. Lets take a look at the Serializer.to_internal_value method.

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

We can see here that the serializer invokes field.run_validation method, which uses model field validators and they raise a DjangoValidationError if validation fails. If it succeeds it'll continue to run any additional validators that are present such as serializer field specific validators (.validate_<field_name>).

Read up more on validation and how it works in Django & DRF here:

  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

Hope this helps to understand how validation works in DRF if even by a bit

EDIT: As long as your field that you're storing emails in is defined to be an EmailField in your models then DRF will validate emails. More on that can be found here



来源:https://stackoverflow.com/questions/53198360/what-types-of-validations-are-automatically-handled-by-django-rest-framework

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!