Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как происходит обработка исключений в Django
Django имеет многоуровневую систему обработки исключений, которая перехватывает ошибки на разных этапах обработки запроса. Это позволяет приложению оставаться стабильным и предоставлять пользователям полезную информацию об ошибке.
1. Жизненный цикл обработки исключения
Когда происходит исключение, Django проходит следующие этапы:
Запрос → Middleware (in) → View → Middleware (out) → Response
↓
Исключение возникает где-то
↓
Exception Middleware перехватывает
↓
Django выбирает обработчик
↓
Возвращает ошибку пользователю
2. Middleware обработка исключений
Django проходит через middleware в обратном порядке при исключении:
# Порядок middleware в settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
# Ваши middleware
]
# Пример custom middleware для перехвата исключений
from django.http import JsonResponse
class ExceptionHandlingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
try:
response = self.get_response(request)
except ValueError as e:
return JsonResponse(
{"error": "Invalid value", "details": str(e)},
status=400
)
except Exception as e:
return JsonResponse(
{"error": "Internal server error"},
status=500
)
return response
3. Встроенные исключения Django
Django предоставляет специальные исключения для разных случаев:
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.core.exceptions import ValidationError, PermissionDenied
# Http404 - автоматически возвращает 404
from django.views import View
class DetailView(View):
def get(self, request, id):
# Вариант 1: автоматический 404
post = get_object_or_404(Post, id=id)
# Вариант 2: явный выброс
if not post:
raise Http404("Post not found")
return render(request, 'post.html', {'post': post})
# PermissionDenied - 403
class AdminView(View):
def get(self, request):
if not request.user.is_staff:
raise PermissionDenied("Access denied")
return render(request, 'admin.html')
# ValidationError для валидации
from django.core.exceptions import ValidationError
def validate_age(age):
if age < 18:
raise ValidationError("Age must be at least 18")
4. Обработчики ошибок (Handler Views)
Django ищет специальные view функции для различных кодов ошибок:
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
# Обработчики ошибок (обычно в главном urls.py)
handler400 = 'myapp.views.bad_request'
handler403 = 'myapp.views.permission_denied'
handler404 = 'myapp.views.page_not_found'
handler500 = 'myapp.views.server_error'
# views.py
def page_not_found(request, exception):
return render(request, '404.html', status=404)
def server_error(request):
return render(request, '500.html', status=500)
5. Сигналы для исключений
Django отправляет сигналы при возникновении исключений:
from django.core.signals import request_started, request_finished
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(request_started)
def log_request_start(sender, **kwargs):
print(f"Request started: {kwargs['request'].path}")
@receiver(request_finished)
def log_request_finish(sender, **kwargs):
print(f"Request finished")
6. Логирование исключений
Django встроенно логирует исключения:
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': 'errors.log',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django': {
'handlers': ['file', 'console'],
'level': 'ERROR',
},
},
}
# В views
import logging
logger = logging.getLogger('django')
def risky_view(request):
try:
result = 10 / 0
except ZeroDivisionError as e:
logger.error(f"Math error: {e}", exc_info=True)
raise
7. DEBUG режим
В DEBUG=True Django показывает подробную информацию об ошибке:
# settings.py
DEBUG = True # На production ВСЕГДА False!
ALLOWED_HOSTS = ['*'] # На production указать конкретные хосты
Этот режим:
- Показывает full stack trace
- Раскрывает переменные и их значения
- Показывает SQL запросы
- НИКОГДА не использовать на production (утечка информации)
8. Custom исключения
class CustomException(Exception):
"""Базовое пользовательское исключение"""
pass
class InsufficientFundsException(CustomException):
"""Недостаточно средств"""
def __init__(self, available, required):
self.available = available
self.required = required
super().__init__(f"Need {required}, have {available}")
# Использование
try:
if balance < amount:
raise InsufficientFundsException(balance, amount)
except InsufficientFundsException as e:
logger.error(f"Payment failed: {e}")
return JsonResponse({"error": str(e)}, status=402)
9. Декоратор для обработки исключений
from functools import wraps
def handle_exceptions(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
try:
return view_func(request, *args, **kwargs)
except Http404:
return render(request, '404.html', status=404)
except PermissionDenied:
return render(request, '403.html', status=403)
except ValidationError as e:
return JsonResponse({"errors": e.message_dict}, status=400)
except Exception as e:
logger.exception("Unexpected error")
return render(request, '500.html', status=500)
return wrapper
@handle_exceptions
def my_view(request):
return render(request, 'page.html')
10. Context processors для ошибок
# context_processors.py
def error_handler(request):
return {
'error': request.GET.get('error'),
'show_debug_info': settings.DEBUG,
}
# settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'context_processors': [
'myapp.context_processors.error_handler',
],
},
},
]
Заключение
Django обеспечивает многоуровневую защиту от исключений: middleware, специальные view функции для ошибок, встроенные исключения для стандартных ситуаций, и логирование. Ключ к надёжному приложению — правильная обработка исключений на каждом уровне, использование специальных исключений Django, и логирование с полезной информацией для отладки.