Data Validation in Django REST Framework (DRF)

January 07, 2026
15 min read
Lalit Mahato
Data Validation in Django REST Framework (DRF)

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:

  1. Field-level validation

  2. Object-level validation

  3. Built-in validators

  4. Custom validators

  5. Model-level validation

  6. Validation in Views

  7. Nested serializer validation


3. Basic Serializer Validation Flow

Typical API request lifecycle:

  1. Request data sent to API

  2. Serializer receives data

  3. serializer.is_valid() is called

  4. Validation logic runs

  5. 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=True in 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.

Lalit Mahato

Lalit Mahato

Software Engineer | Machine Learning Enthusiast

Innovative and results-driven software developer with 5+ years of experience in designing, developing, and deploying high-quality software solutions. Proficient in various programming languages and technologies, with a keen interest in …

Comments (0)

No comments yet. Be the first to comment!

Leave a Comment

Search

Categories

Related Posts

Mastering Custom Pagination in Django Rest Framework
Mastering Custom Pagination in Django Rest Framework

Jan 08, 2026

Read More
Mastering Token Authentication with Django Rest Framework & Swagger
Mastering Token Authentication with Django Rest Framework & Swagger

Jan 08, 2026

Read More
Building an API with Django REST Framework
Building an API with Django REST Framework

Jan 03, 2026

Read More