""" هندلرِ سفارشیِ exception برای DRF: هندلرِ پیش‌فرض فقط APIException/Http404/ PermissionDenied رو می‌شناسه؛ برای بقیه None برمی‌گردونه و exception خام تا مدیریتِ خطای جنگو بالا می‌ره که (DEBUG=False) یه صفحه‌ی HTML عمومی می‌ده، نه JSON. این هندلر اون حالت رو با traceback کامل لاگ می‌کنه و یه پاسخِ JSON ژنریکِ ۵۰۰ برمی‌گردونه. """ import logging from django.core.exceptions import RequestDataTooBig, SuspiciousOperation from config.db import SERVER_BUSY_BODY, SERVER_BUSY_RETRY_AFTER, is_pool_timeout, log_server_busy from rest_framework.response import Response from rest_framework.views import exception_handler as drf_exception_handler logger = logging.getLogger(__name__) def custom_exception_handler(exc, context): response = drf_exception_handler(exc, context) if response is not None: return response request = context.get('request') path = getattr(request, 'path', '') # بدنه‌ی بزرگ‌تر از DATA_UPLOAD_MAX_MEMORY_SIZE (≈ ۲٫۵ مگابایت): Django خودش این را ۴۰۰ می‌کند، ولی # چون DRF آن را نمی‌شناسد پیش‌تر اینجا «۵۰۰ + ERRORِ لاگ با traceback» می‌شد و هر درخواستِ بزرگ لاگ را پر # می‌کرد (۲۰۲۶-۱۰-۰۷ روی سرورِ زنده دیده شد). باقیِ SuspiciousOperationها هم همان ۴۰۰ِ Django را می‌گیرند. # poolِ دیتابیس پر (config/db.py): ۵۰۳ با Retry-After. پیش از خواندنِ request.user پایین‌تر، که اگر # احرازِ هویت خودش همین خطا را داده بود دوباره منتظرِ pool می‌ماند. if is_pool_timeout(exc): log_server_busy(request) return Response(SERVER_BUSY_BODY, status=503, headers={'Retry-After': str(SERVER_BUSY_RETRY_AFTER)}) if isinstance(exc, RequestDataTooBig): logger.warning('request_too_large path=%s', path) return Response({'detail': 'حجمِ درخواست بیش از حدِ مجاز است.'}, status=413) if isinstance(exc, SuspiciousOperation): logger.warning('suspicious_operation path=%s type=%s', path, type(exc).__name__) return Response({'detail': 'درخواستِ نامعتبر.'}, status=400) user = getattr(request, 'user', None) user_id = user.id if getattr(user, 'is_authenticated', False) else None logger.exception( 'unhandled_exception path=%s user_id=%s', path, user_id, ) return Response( {'detail': 'خطای غیرمنتظره‌ای رخ داد؛ لطفاً بعداً دوباره تلاش کنید.'}, status=500, )