Click to jump to the REST-Framework column directory

When you use the REST framework for validation processing, you might just rely on the default field validation or use explicit validation on serializer, but if you put the validation logic in a reusable component, you can reuse the code and reduce redundancy. This can be done by validating classes or functions.

Example description:

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

CustomerReportSerializer is the basis for creating or updating instances of CustomerReportRecord:

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

Using Django-shell, you can execute to get the following information:

>>> 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())>])
    description = CharField(style={'type': 'textarea'})
Copy the code

UniqueValidator

Validation class for model field constraints with unique=True.

parameter

  • queryset: mandatory parameter for the query set that executes the constraint
  • message: Error message returned after authentication failure
  • lookup: Lookup for finding existing instances with values being validated. The default is"exact"

The sample

from rest_framework.validators import UniqueValidator

class. :. slug = SlugField( max_length=100,
        validators=[UniqueValidator(queryset=BlogPost.objects.all()))Copy the code

UniqueTogetherValidator

This validation class is used for combination constraints under multiple fields.

parameter

  • queryset: mandatory parameter for the query set that executes the constraint
  • message: Error message returned after authentication failure
  • fields: mandatory argument, used to combine a list of fields or tuples of unique constraints

The sample

from rest_framework.validators import UniqueTogetherValidator

class ExampleSerializer(serializers.Serializer) :.class Meta:
        validators = [
            UniqueTogetherValidator(
                queryset=ToDoItem.objects.all(),
                fields=['list'.'position']]Copy the code

UniqueForMonthValidator, UniqueForYearValidator

These three validation classes are used to constrain the time model field.

parameter

  • queryset: mandatory parameter for the query set that executes the constraint
  • message: Error message returned after authentication failure
  • field: Mandatory parameter, time field name for the constraint
  • date_field: mandatory argument used to determine the date range of the uniqueness constraint

The sample

from rest_framework.validators import UniqueForYearValidator

class ExampleSerializer(serializers.Serializer) :.class Meta:
        validators = [
            UniqueForYearValidator(
                queryset=BlogPostItem.objects.all(),
                field='slug',
                date_field='published')]Copy the code

Serializer always requires a date field for validation. You can’t simply rely on the model class Default =… Because the values used for default values are not generated until validation runs.

Depending on how you want the API to behave, you may need to use some styles, and if you are using ModelSerializer, you may just rely on the default values generated for you by the REST Framework, But if you’re using Serializer or just want more explicit control, use one of the styles demonstrated below.

Used with writable date fields

If you want the date field to be writable, the only thing to note is that you can ensure that the date field in the input data is always available by setting the default parameter or required=True.

published = serializers.DateTimeField(required=True)
Copy the code

Used with read-only date fields

If you want the date field to be visible but not editable by the user, set read_only=True and an additional default=… Parameters.

published = serializers.DateTimeField(read_only=True, default=timezone.now)
Copy the code

Use with hidden date fields

If you want the date field to be completely hidden from the user, use the HiddenField, which does not accept user input but always returns its default value to validATED_data in the serializer.

published = serializers.HiddenField(default=timezone.now)
Copy the code

Default value Advanced usage

CurrentUserDefault

The default class that can be used to represent the current user. If you want to use it, ‘request’ must be provided as part of the context dictionary when instantiating the serializer.

owner = serializers.HiddenField(
    default=serializers.CurrentUserDefault()
)
Copy the code

CreateOnlyDefault

Used as a default value at creation time and ignored during update operations.

created_at = serializers.DateTimeField(
    default=serializers.CreateOnlyDefault(timezone.now)
)
Copy the code

Complex validation

In cases where explicit validation is not sufficient for your validation needs, overriding the validate method in the Serializer class is a good idea.

class BillingRecordSerializer(serializers.ModelSerializer) :
    def validate(self, attrs) :
        # Apply custom validation either here, or in the view.

    class Meta:
        fields = ['client'.'date'.'amount']
        extra_kwargs = {'client': {'required': False}}
        validators = []  # Remove a default "unique together" constraint.
Copy the code

Custom authentication

The validator is can trigger serializers. Any callable object ValidationError anomalies, such as:

def even_number(value) :
    if value % 2! =0:
        raise serializers.ValidationError('This field must be an even number.')
Copy the code

Of course, you can use the Serializer you define to validate a particular field as follows:

class BillingRecordSerializer(serializers.ModelSerializer) :
    def validate_title(self, attrs) :
        # Apply custom validation either here, or in the view.
Copy the code

The format is to define the.validate_

method in Serializer.

The __call__ method can be overridden by defining the validator as a class, which is more reusable:

class MultipleOf:
    def __init__(self, base) :
        self.base = base

    def __call__(self, value) :
        ifvalue % self.base ! =0:
            message = 'This field must be a multiple of %d.' % self.base
            raise serializers.ValidationError(message)
Copy the code

In some advanced cases, you might want to pass the serializer field used with it to the validator as an additional context, which you can do by setting the requiRES_context = True attribute on the validator, The __call__ method is then called with serializer_field or serializer as additional arguments.

requires_context = True

def __call__(self, value, serializer_field) :.Copy the code