← Назад к вопросам
Как вернуть в Django ответ с сервера, если пришли некорректные данные с клиента?
1.2 Junior🔥 161 комментариев
#Django#REST API и HTTP
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Возврат ошибок валидации в Django
Общие принципы
В Django есть несколько уровней обработки ошибок валидации:
- Form валидация — для HTML форм
- Model валидация — на уровне БД и модели
- API JSON ответы — для REST API
- Исключения — для обработки ошибок
Подход 1: Django Forms
Для традиционных HTML форм:
from django import forms
from django.http import JsonResponse
from django.views import View
class UserForm(forms.Form):
username = forms.CharField(
min_length=3,
max_length=50,
error_messages={
'required': 'Username is required',
'min_length': 'Username too short',
'max_length': 'Username too long',
}
)
email = forms.EmailField(
error_messages={
'invalid': 'Invalid email format',
'required': 'Email is required',
}
)
age = forms.IntegerField(
min_value=18,
max_value=120,
error_messages={
'min_value': 'Age must be >= 18',
'max_value': 'Age must be <= 120',
}
)
class CreateUserView(View):
def post(self, request):
form = UserForm(request.POST)
if form.is_valid():
# Данные корректны
username = form.cleaned_data['username']
email = form.cleaned_data['email']
age = form.cleaned_data['age']
# Создание пользователя
user = User.objects.create(
username=username,
email=email,
age=age
)
return JsonResponse({'user_id': user.id})
else:
# Ошибки валидации
return JsonResponse(
{'errors': form.errors},
status=400
)
Подход 2: Model валидация
Проверка на уровне модели:
from django.db import models
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator, MaxValueValidator
class User(models.Model):
username = models.CharField(
max_length=50,
unique=True,
validators=[]
)
email = models.EmailField(unique=True)
age = models.IntegerField(
validators=[
MinValueValidator(18, 'Age must be >= 18'),
MaxValueValidator(120, 'Age must be <= 120'),
]
)
def clean(self):
"""Контекстная валидация"""
errors = {}
# Проверка уникальности
if User.objects.filter(username=self.username).exclude(pk=self.pk).exists():
errors['username'] = 'Username already exists'
# Бизнес-правила
if self.age < 18:
errors['age'] = 'Must be adult'
if errors:
raise ValidationError(errors)
def save(self, *args, **kwargs):
# Всегда вызывайте clean() перед save()
self.full_clean() # Вызывает clean() и валидирует поля
super().save(*args, **kwargs)
# В представлении
from django.core.exceptions import ValidationError
def create_user_view(request):
try:
user = User(
username=request.POST['username'],
email=request.POST['email'],
age=int(request.POST['age'])
)
user.full_clean() # Валидация
user.save()
return JsonResponse({'user_id': user.id})
except ValidationError as e:
# Словарь ошибок по полям
return JsonResponse(
{'errors': e.message_dict},
status=400
)
except (KeyError, ValueError) as e:
return JsonResponse(
{'errors': {'general': str(e)}},
status=400
)
Подход 3: REST Framework (DRF) — рекомендуемый
Django REST Framework — идеален для JSON API:
from rest_framework import serializers, viewsets, status
from rest_framework.response import Response
from rest_framework.decorators import api_view
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'age']
extra_kwargs = {
'username': {
'min_length': 3,
'max_length': 50,
'error_messages': {
'required': 'Username required',
'blank': 'Username cannot be blank',
'max_length': 'Username too long',
'min_length': 'Username too short',
}
},
'email': {
'required': True,
},
'age': {
'min_value': 18,
'max_value': 120,
'error_messages': {
'min_value': 'Age >= 18',
'max_value': 'Age <= 120',
}
}
}
def validate_username(self, value):
"""Field-level валидация"""
if User.objects.filter(username=value).exists():
raise serializers.ValidationError(
'Username already exists'
)
return value.lower()
def validate(self, data):
"""Object-level валидация"""
# Проверки на уровне объекта
if data.get('age', 0) < 18:
raise serializers.ValidationError({
'age': 'User must be adult'
})
return data
class UserViewSet(viewsets.ViewSet):
def create(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(
serializer.data,
status=status.HTTP_201_CREATED
)
# Автоматически возвращает ошибки в JSON
return Response(
serializer.errors,
status=status.HTTP_400_BAD_REQUEST
)
# Использование в URLs
from django.urls import path
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
urlpatterns = router.urls
Структура JSON ошибок
Традиционная структура:
{
"errors": {
"username": ["Username is required"],
"email": ["Invalid email format"],
"age": ["Age must be >= 18"]
}
}
DRF структура (по умолчанию):
{
"username": ["Username is required"],
"email": ["Invalid email format"],
"age": ["Age must be >= 18"]
}
Кастомный обработчик ошибок
from rest_framework.exceptions import APIException
from rest_framework.views import exception_handler
import logging
logger = logging.getLogger(__name__)
class ValidationAPIException(APIException):
status_code = 400
default_detail = 'Validation error'
def custom_exception_handler(exc, context):
"""Кастомный обработчик исключений"""
response = exception_handler(exc, context)
if response is not None:
# Логируем ошибку
logger.warning(
f'Validation error: {response.data}',
extra={'user': context['request'].user}
)
# Преобразуем в нашу структуру
response.data = {
'success': False,
'errors': response.data,
'message': 'Validation failed'
}
return response
# Настройка в settings.py
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'your_app.utils.custom_exception_handler',
}
Полный пример с обработкой
from django.views.decorators.http import require_http_methods
from django.http import JsonResponse
import json
import logging
logger = logging.getLogger(__name__)
@require_http_methods(["POST"])
def create_user_api(request):
try:
# Парсинг JSON
data = json.loads(request.body)
except json.JSONDecodeError:
return JsonResponse(
{'error': 'Invalid JSON'},
status=400
)
# Валидация
errors = {}
username = data.get('username', '').strip()
if not username:
errors['username'] = 'Required'
elif len(username) < 3:
errors['username'] = 'Too short (min 3)'
elif len(username) > 50:
errors['username'] = 'Too long (max 50)'
email = data.get('email', '').strip().lower()
if not email:
errors['email'] = 'Required'
elif '@' not in email:
errors['email'] = 'Invalid format'
age = data.get('age')
try:
age = int(age)
if age < 18 or age > 120:
errors['age'] = 'Must be 18-120'
except (TypeError, ValueError):
errors['age'] = 'Must be integer'
if errors:
logger.warning(f'Validation failed: {errors}')
return JsonResponse(
{'success': False, 'errors': errors},
status=400
)
# Создание
try:
user = User.objects.create(
username=username,
email=email,
age=age
)
return JsonResponse(
{'success': True, 'user_id': user.id},
status=201
)
except Exception as e:
logger.error(f'User creation failed: {e}')
return JsonResponse(
{'success': False, 'error': 'Server error'},
status=500
)
Лучшие практики
- Используйте DRF для JSON API
- Всегда вызывайте
full_clean()на моделях перед save - Логируйте ошибки валидации без деталей клиенту
- Структурируйте ошибки по полям для удобства клиента
- Возвращайте правильные HTTP статусы (400 для валидации)
- Не передавайте внутренние ошибки — скрывайте детали реализации
- Валидируйте на нескольких уровнях — форма, модель, представление
Django обеспечивает мощную систему валидации на всех уровнях приложения.