问题
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:
- Form Field Validation Django 2.1
- Validators - DRF Docs
- Serializer Validation - DRF Docs
- Correct way to validate Django Models
- 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