Data Validation in Django REST Framework (DRF)
Data validation is one of the most critical parts of building secure and reliable APIs. Django REST Framework provides a powerful and flexible validation system that works at multiple levels.
This guide explains all validation methods in DRF, from basic to advanced, with clear examples.
1. What Is Validation in DRF?
Validation ensures that:
-
Incoming data is correct
-
Required fields are present
-
Data follows business rules
-
Invalid or malicious data is rejected before saving to the database
In DRF, validation mainly happens in serializers.
2. Types of Validation in DRF
DRF supports validation at multiple levels:
-
Field-level validation
-
Object-level validation
-
Built-in validators
-
Custom validators
-
Model-level validation
-
Validation in Views
-
Nested serializer validation
3. Basic Serializer Validation Flow
Typical API request lifecycle:
-
Request data sent to API
-
Serializer receives data
-
serializer.is_valid()is called -
Validation logic runs
-
Errors returned or data saved
Example:
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
4. Field-Level Validation
4.1 Using validate_<field_name>
Use this when validation logic applies to only one field.
Example:
from rest_framework import serializers
class UserSerializer(serializers.Serializer):
username = serializers.CharField()
age = serializers.IntegerField()
def validate_age(self, value):
if value < 18:
raise serializers.ValidationError("Age must be 18 or above.")
return value
✔ Runs automatically
✔ Clean and readable
✔ Best for single-field rules
5. Object-Level Validation
Use object-level validation when validation depends on multiple fields.
5.1 Using validate(self, attrs)
Example:
class UserSerializer(serializers.Serializer):
password = serializers.CharField()
confirm_password = serializers.CharField()
def validate(self, attrs):
if attrs['password'] != attrs['confirm_password']:
raise serializers.ValidationError(
{"confirm_password": "Passwords do not match."}
)
return attrs
✔ Ideal for cross-field checks
✔ Executes after field-level validation
6. Built-in Field Validators
DRF provides many built-in validations.
6.1 Required Fields
email = serializers.EmailField(required=True)
6.2 Allow Null / Blank
name = serializers.CharField(allow_blank=True, allow_null=True)
6.3 Max / Min Length
username = serializers.CharField(min_length=3, max_length=20)
6.4 Numeric Constraints
price = serializers.IntegerField(min_value=1, max_value=10000)
7. Using Django Validators
You can reuse Django’s validators.
Example:
from django.core.validators import RegexValidator
phone_validator = RegexValidator(
regex=r'^\+?1?\d{9,15}$',
message="Enter a valid phone number."
)
class UserSerializer(serializers.Serializer):
phone = serializers.CharField(validators=[phone_validator])
✔ Reusable
✔ Clean
✔ Centralized validation logic
8. Custom Validators (Reusable)
Custom validators are useful when the same rule is used in multiple serializers.
8.1 Function-Based Validator
from rest_framework import serializers
def validate_even(value):
if value % 2 != 0:
raise serializers.ValidationError("Value must be an even number.")
Usage:
class SampleSerializer(serializers.Serializer):
number = serializers.IntegerField(validators=[validate_even])
8.2 Class-Based Validator
class MinimumAmountValidator:
def __init__(self, min_amount):
self.min_amount = min_amount
def __call__(self, value):
if value < self.min_amount:
raise serializers.ValidationError(
f"Amount must be at least {self.min_amount}"
)
Usage:
amount = serializers.IntegerField(
validators=[MinimumAmountValidator(100)]
)
9. ModelSerializer Validation
When using ModelSerializer, DRF automatically applies:
-
Model field constraints
-
blank=False,null=False -
unique=True
Example:
class User(models.Model):
email = models.EmailField(unique=True)
If duplicate email is sent:
{
"email": ["user with this email already exists."]
}
10. Using Meta.validators
Apply validation at serializer level.
Example:
from rest_framework.validators import UniqueTogetherValidator
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = "__all__"
validators = [
UniqueTogetherValidator(
queryset=Order.objects.all(),
fields=['user', 'product']
)
]
✔ Ensures unique combinations
✔ Clean database-level safety
11. Validation Errors Format
Standard DRF error response:
{
"field_name": [
"Error message"
]
}
Object-level error:
{
"non_field_errors": [
"Custom error message"
]
}
12. Raising Validation Errors Correctly
Always use:
from rest_framework import serializers
raise serializers.ValidationError("Message")
Or field-specific:
raise serializers.ValidationError({
"field": "Error message"
})
13. Validation in Views (Advanced)
Sometimes validation logic belongs in the view.
Example:
def post(self, request):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
if not request.user.is_staff:
raise PermissionDenied("Only staff users allowed.")
serializer.save()
✔ Use sparingly
✔ Best for permission-based validation
14. Nested Serializer Validation
Validation in nested serializers works automatically.
Example:
class ProfileSerializer(serializers.Serializer):
bio = serializers.CharField()
class UserSerializer(serializers.Serializer):
username = serializers.CharField()
profile = ProfileSerializer()
If nested validation fails, errors are nested:
{
"profile": {
"bio": ["This field is required."]
}
}
15. Best Practices
-
Use field-level validation whenever possible
-
Use object-level validation for cross-field logic
-
Prefer custom reusable validators for repeated rules
-
Keep validation logic out of views unless necessary
-
Always use
raise_exception=Truein APIs -
Never trust frontend validation alone
16. Validation Checklist (For Production APIs)
✔ Required fields checked
✔ Type validation handled
✔ Business rules enforced
✔ Unique constraints applied
✔ Clear error messages returned
✔ No database writes before validation
17. Conclusion
Django REST Framework provides a robust, layered validation system that allows you to:
-
Validate simple fields
-
Enforce complex business rules
-
Reuse validation logic
-
Keep APIs clean and secure
Mastering serializer validation is essential for building professional-grade REST APIs in Django.