Глобальная обработка исключений в Django-rest-framework

Есть ли способ обрабатывать все исключения глобально без использования блока try-except в фреймворке django rest.

Я хочу преобразовать страницу ошибки html, которую django выдает, в настроенный ответ объекта json.

Я создал файл exception.py в своем приложении.

def custom_exception_handler(exc, context=None):
    response = exception_handler(exc)


    if isinstance(exc, HttpResponseServerError):  
        custom_response_data = { 
            'detail': 'Internal Server Error' # custom exception message
        }
        response.data = custom_response_data

    return response

я настроил это в settings.py.

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'EXCEPTION_HANDLER':'my_project.my_app.exceptions.custom_exception_handler'}

person Shubham Kumar    schedule 27.02.2020    source источник
comment
Вы можете написать собственное ПО промежуточного слоя, которое обрабатывает исключения. Однако это не обрабатывает исключения других промежуточных программ AFAIU.   -  person tahesse    schedule 27.02.2020
comment
@ Томас Гессе, не могли бы вы привести пример?   -  person Shubham Kumar    schedule 28.02.2020
comment
Я дал ответ, надеясь, что это поможет вам. На самом деле в этом нет ничего нового, но, надеюсь, он поможет вам в качестве отправной точки.   -  person tahesse    schedule 28.02.2020


Ответы (2)


Поскольку я столкнулся с похожей ситуацией, которая привела меня к этому вопросу, я отвечу на исходный вопрос, который конкретно связан с Django Rest Framework, а не только с Django.

Я понимаю, что вы хотите обрабатывать возникающие исключения из ваших представлений глобально, без необходимости определять блоки try/except в каждом модуле представления.

DRF позволяет определить собственный механизм обработки особых исключений (документы). Вот пример:

В my_custom_except_handler.py:

import logging
from rest_framework.views import exception_handler
from django.http import JsonResponse
from requests import ConnectionError

def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first
    response = exception_handler(exc, context)

    # checks if the raised exception is of the type you want to handle
    if isinstance(exc, ConnectionError):
        # defines custom response data
        err_data = {'MSG_HEADER': 'some custom error messaging'}

        # logs detail data from the exception being handled
        logging.error(f"Original error detail and callstack: {exc}")
        # returns a JsonResponse
        return JsonResponse(err_data, safe=False, status=503)

    # returns response as handled normally by the framework
    return response

Как указано в документах, определенный объект ответа относится к:

Функция обработчика исключений должна либо возвращать объект Response, либо возвращать None, если исключение не может быть обработано. Если обработчик вернет None, то исключение будет сгенерировано повторно, и Django вернет стандартный ответ HTTP 500 «ошибка сервера».

Другими словами, "ответ" не будет None только при обработке этих исключений документы:

  • Подклассы APIException.
  • Исключение Django Http404.
  • Исключение Django PermissionDenied.

Если ваш пользовательский обработчик возвращает None, то исключение будет обрабатываться фреймворком "обычно", возвращая типичную ошибку сервера 500.

Наконец, не забудьте установить необходимый ключ в settings.py:

REST_FRAMEWORK = {'EXCEPTION_HANDLER': 
    'my_project.my_app.my_custom_except_handler.custom_exception_handler'}

Надеюсь, поможет!

person NicoE    schedule 26.06.2020
comment
это очень полезно, спасибо - person bigOther; 27.12.2020

Однозначный ответ на ваш вопрос: нет.

По крайней мере, я не знаю, как это сделать глобально в Django, тогда как глобально включает исключения промежуточного ПО).

Кроме того, по запросу @Shubham Kumar вам нужен хук process_exception, а для реализации проверьте это сообщение SO с помощью официальные документы о том, как его активировать. Как указано в документах Django:

запрос является объектом HttpRequest. исключение — это объект Exception, созданный функцией представления.

Django вызывает process_exception(), когда представление вызывает исключение. process_exception() должен возвращать либо None, либо объект HttpResponse. Если он возвращает объект HttpResponse, будут применены ответ шаблона и ПО промежуточного слоя ответа, а результирующий ответ будет возвращен в браузер. В противном случае срабатывает обработка исключений по умолчанию.

Опять же, промежуточное ПО запускается в обратном порядке на этапе ответа, который включает в себя process_exception. Если промежуточное программное обеспечение исключения возвращает ответ, методы process_exception классов промежуточного программного обеспечения выше этого промежуточного программного обеспечения вообще не будут вызываться.

Это означает, что вы просто сможете подключиться к функции просмотра и перехватить все эти исключения.

person tahesse    schedule 28.02.2020