Validators can be useful for reusing validation logic between different types of fields. REST framework includes several validator classes that enforce various constraints.
UniqueValidator
Enforces the unique=True constraint on model fields.
Class Signature
UniqueValidator(
queryset,
message=None,
lookup='exact'
)
Queryset against which uniqueness is enforced.
Custom error message. Defaults to 'This field must be unique.'
Lookup type for finding existing instances.
Usage
Apply to serializer fields:
from rest_framework.validators import UniqueValidator
class BlogPostSerializer(serializers.Serializer):
slug = serializers.SlugField(
max_length=100,
validators=[UniqueValidator(queryset=BlogPost.objects.all())]
)
Example
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField(
validators=[UniqueValidator(queryset=User.objects.all())]
)
class Meta:
model = User
fields = ['username', 'email']
UniqueTogetherValidator
Enforces unique_together constraints on model instances.
Class Signature
UniqueTogetherValidator(
queryset,
fields,
message=None,
condition_fields=None,
condition=None,
code=None
)
Queryset against which uniqueness is enforced.
List of field names that must form a unique set.
Custom error message. Defaults to 'The fields {field_names} must make a unique set.'
Additional fields required by the condition.
Django Q object for conditional uniqueness.
Error code for validation failures.
Usage
Apply to serializer classes:
from rest_framework.validators import UniqueTogetherValidator
class ToDoItemSerializer(serializers.Serializer):
list = serializers.PrimaryKeyRelatedField(queryset=ToDoList.objects.all())
position = serializers.IntegerField()
title = serializers.CharField(max_length=100)
class Meta:
validators = [
UniqueTogetherValidator(
queryset=ToDoItem.objects.all(),
fields=['list', 'position']
)
]
Example
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields = ['room_number', 'date', 'name']
validators = [
UniqueTogetherValidator(
queryset=Event.objects.all(),
fields=['room_number', 'date'],
message='Each room can only have one event per day.'
)
]
Note: All fields in UniqueTogetherValidator are implicitly required unless they have a default value.
UniqueForDateValidator
Enforces unique_for_date constraint.
Class Signature
UniqueForDateValidator(
queryset,
field,
date_field,
message=None
)
Queryset against which uniqueness is enforced.
Field name to validate for uniqueness.
Field name to use for date range.
Custom error message. Defaults to 'This field must be unique for the "{date_field}" date.'
Usage
from rest_framework.validators import UniqueForDateValidator
class BlogPostSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPost
fields = ['slug', 'published', 'title']
validators = [
UniqueForDateValidator(
queryset=BlogPost.objects.all(),
field='slug',
date_field='published'
)
]
Date Field Styles
Writable date field:
published = serializers.DateTimeField(required=True)
Read-only date field:
published = serializers.DateTimeField(read_only=True, default=timezone.now)
Hidden date field:
published = serializers.HiddenField(default=timezone.now)
Enforces unique_for_month constraint.
Class Signature
UniqueForMonthValidator(
queryset,
field,
date_field,
message=None
)
Queryset against which uniqueness is enforced.
Field name to validate for uniqueness.
Field name to use for month range.
Custom error message. Defaults to 'This field must be unique for the "{date_field}" month.'
Example
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ['slug', 'published', 'title']
validators = [
UniqueForMonthValidator(
queryset=Article.objects.all(),
field='slug',
date_field='published'
)
]
UniqueForYearValidator
Enforces unique_for_year constraint.
Class Signature
UniqueForYearValidator(
queryset,
field,
date_field,
message=None
)
Queryset against which uniqueness is enforced.
Field name to validate for uniqueness.
Field name to use for year range.
Custom error message. Defaults to 'This field must be unique for the "{date_field}" year.'
Example
class BlogPostSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPost
fields = ['slug', 'published', 'title']
validators = [
UniqueForYearValidator(
queryset=BlogPost.objects.all(),
field='slug',
date_field='published'
)
]
Default Classes
CurrentUserDefault
Default class that returns the current user.
Requires request in serializer context.
Example:
owner = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
CreateOnlyDefault
Default class that sets a value only during create operations.
CreateOnlyDefault(default)
Default value or callable for create operations.
Example:
created_at = serializers.DateTimeField(
default=serializers.CreateOnlyDefault(timezone.now)
)
Custom Validators
Function-Based Validator
def even_number(value):
if value % 2 != 0:
raise serializers.ValidationError('This field must be an even number.')
class GameRecordSerializer(serializers.Serializer):
score = serializers.IntegerField(validators=[even_number])
Class-Based Validator
class MultipleOf:
def __init__(self, base):
self.base = base
def __call__(self, value):
if value % self.base != 0:
message = 'This field must be a multiple of %d.' % self.base
raise serializers.ValidationError(message)
class GameRecordSerializer(serializers.Serializer):
score = serializers.IntegerField(validators=[MultipleOf(10)])
Context-Aware Validator
class MultipleOf:
requires_context = True
def __init__(self, base):
self.base = base
def __call__(self, value, serializer_field):
if value % self.base != 0:
message = 'This field must be a multiple of %d.' % self.base
raise serializers.ValidationError(message)
Disabling Validators
Disable automatically generated validators:
class BillingRecordSerializer(serializers.ModelSerializer):
def validate(self, attrs):
# Custom validation logic here
return attrs
class Meta:
model = BillingRecord
fields = ['client', 'date', 'amount']
extra_kwargs = {'client': {'required': False}}
validators = [] # Disable automatic validators
Limitations
Optional Fields
For optional fields in unique_together constraints:
class Meta:
validators = [] # Disable automatic validator
def validate(self, attrs):
# Implement custom validation logic
if 'field1' in attrs and 'field2' in attrs:
# Check uniqueness
pass
return attrs
Nested Serializers
For nested serializers, uniqueness validators may need to be disabled:
class ParentSerializer(serializers.ModelSerializer):
children = ChildSerializer(many=True)
class Meta:
model = Parent
fields = ['name', 'children']
# ChildSerializer should have validators=[] if needed