← Назад к вопросам

На чем делаешь валидацию входных данных в DRF

2.0 Middle🔥 291 комментариев
#Django#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Валидация входных данных в Django Rest Framework

DRF предоставляет мощный встроенный механизм валидации данных. Валидация — это критически важный процесс для обеспечения целостности и безопасности приложения.

1. Валидация на уровне полей (Field-level validation)

Это первый уровень валидации, который срабатывает автоматически для каждого поля в сериализаторе.

from rest_framework import serializers

class UserSerializer(serializers.Serializer):
    username = serializers.CharField(
        max_length=150,
        min_length=3,
        required=True
    )
    email = serializers.EmailField()
    age = serializers.IntegerField(
        min_value=0,
        max_value=150
    )
    phone = serializers.CharField(
        max_length=20,
        allow_blank=False
    )

DRF автоматически проверит формат email, диапазоны для целых чисел и строковые ограничения.

2. Методы-валидаторы на уровне полей (validate_field_name)

Для более сложной логики валидации одного поля можно использовать методы validate_<field_name>.

class UserSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=150)
    email = serializers.EmailField()
    age = serializers.IntegerField()
    
    def validate_username(self, value):
        """Проверяем, что username не содержит недопустимые символы"""
        if not value.isalnum():
            raise serializers.ValidationError(
                "Username может содержать только буквы и цифры"
            )
        return value
    
    def validate_age(self, value):
        """Проверяем возраст"""
        if value < 18:
            raise serializers.ValidationError(
                "Пользователь должен быть старше 18 лет"
            )
        return value

3. Валидация на уровне объекта (validate method)

Для проверки корреляции между несколькими полями используем метод validate.

class PasswordChangeSerializer(serializers.Serializer):
    old_password = serializers.CharField(write_only=True)
    new_password = serializers.CharField(write_only=True)
    new_password_confirm = serializers.CharField(write_only=True)
    
    def validate(self, data):
        """Проверяем согласованность паролей"""
        if data["new_password"] != data["new_password_confirm"]:
            raise serializers.ValidationError(
                {"new_password_confirm": "Пароли не совпадают"}
            )
        
        if data["new_password"] == data["old_password"]:
            raise serializers.ValidationError(
                {"new_password": "Новый пароль совпадает со старым"}
            )
        
        return data

4. Кастомные валидаторы (validators)

Для переиспользуемой логики валидации создают отдельные функции-валидаторы.

def validate_even_number(value):
    """Проверяет, что число четное"""
    if value % 2 != 0:
        raise serializers.ValidationError(
            "Это число не четное"
        )

def validate_no_profanity(value):
    """Проверяет отсутствие запрещенных слов"""
    forbidden_words = ["bad", "ugly"]
    if any(word in value.lower() for word in forbidden_words):
        raise serializers.ValidationError(
            "Текст содержит недопустимые слова"
        )

class ProductSerializer(serializers.Serializer):
    name = serializers.CharField(validators=[validate_no_profanity])
    quantity = serializers.IntegerField(validators=[validate_even_number])

5. Валидация на уровне ModelSerializer

При использовании ModelSerializer валидация тесно интегрирована с моделью Django.

from django.contrib.auth.models import User

class UserModelSerializer(serializers.ModelSerializer):
    password_confirm = serializers.CharField(
        write_only=True,
        required=True
    )
    
    class Meta:
        model = User
        fields = ["username", "email", "password", "password_confirm"]
        extra_kwargs = {
            "password": {"write_only": True, "min_length": 8}
        }
    
    def validate(self, data):
        if data["password"] != data.pop("password_confirm"):
            raise serializers.ValidationError(
                {"password_confirm": "Пароли не совпадают"}
            )
        return data
    
    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user

6. Валидация в представлении (View-level validation)

Иногда нужна валидация, которая зависит от контекста запроса (например, проверка прав доступа).

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class CreateOrderView(APIView):
    def post(self, request):
        serializer = OrderSerializer(data=request.data)
        
        # Сначала базовая валидация
        if not serializer.is_valid():
            return Response(
                serializer.errors,
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Затем проверка прав и бизнес-логики
        if not request.user.is_authenticated:
            return Response(
                {"detail": "Требуется аутентификация"},
                status=status.HTTP_401_UNAUTHORIZED
            )
        
        if not request.user.has_balance():
            return Response(
                {"detail": "Недостаточно средств"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        order = serializer.save(user=request.user)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

7. Встроенные валидаторы DRF

DRF предоставляет готовые валидаторы для часто встречающихся случаев:

from rest_framework.validators import (
    UniqueValidator,
    UniqueTogetherValidator
)

class ArticleSerializer(serializers.ModelSerializer):
    slug = serializers.SlugField(
        validators=[UniqueValidator(queryset=Article.objects.all())]
    )
    
    class Meta:
        model = Article
        fields = ["title", "slug", "author", "published_date"]
        validators = [
            UniqueTogetherValidator(
                queryset=Article.objects.all(),
                fields=["author", "published_date"],
                message="Автор не может опубликовать две статьи в один день"
            )
        ]

Лучшие практики валидации

  • Ранняя валидация — проверяйте данные как можно раньше в процессе обработки
  • Понятные сообщения об ошибках — помогите пользователю понять, что не так
  • Разделение ответственности — не смешивайте валидацию с бизнес-логикой
  • Переиспользование валидаторов — создавайте кастомные валидаторы для повторяющейся логики
  • Логирование ошибок валидации — отслеживайте попытки передачи невалидных данных

Валидация в DRF — это мощный инструмент, который при правильном использовании значительно упрощает разработку и повышает качество приложения.