Добавить поле к исключениям DRF.PermissionDenied

Сейчас django-rest-framework's exceptions.PermissionDenied возвращает 403 и подробное сообщение: "У вас нет разрешения на выполнение этого действия"

{"detail": "You don't have permission to perform this action."}

Я хотел бы расширить это, чтобы включить поле "причина", так что я могу сделать что-то вроде `MyException(detail="Some detail here", reason="INSUFFICIENT_TIER"). но detail, кажется, цепочка довольно далеко вверх и преобразуется в довольно многих местах. Кто-нибудь знает, как я могу легко добавить поле, которое будет возвращено в json выше?

Вот исключение DRF для справки.

class PermissionDenied(APIException):
    status_code = status.HTTP_403_FORBIDDEN
    default_detail = _('You do not have permission to perform this action.')
    default_code = 'permission_denied'

It extends APIException:

class APIException(Exception):
    """
    Base class for REST framework exceptions.
    Subclasses should provide `.status_code` and `.default_detail` properties.
    """
    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    default_detail = _('A server error occurred.')
    default_code = 'error'

    def __init__(self, detail=None, code=None):
        if detail is None:
            detail = self.default_detail
        if code is None:
            code = self.default_code

        self.detail = _get_error_details(detail, code)

    def __str__(self):
        return str(self.detail)

    def get_codes(self):
        """
        Return only the code part of the error details.

        Eg. {"name": ["required"]}
        """
        return _get_codes(self.detail)

    def get_full_details(self):
        """
        Return both the message & code parts of the error details.

        Eg. {"name": [{"message": "This field is required.", "code": "required"}]}
        """
        return _get_full_details(self.detail)

Вы можете создать свой собственный PermissionClass. Для вашего случая это будет выглядеть следующим образом:

from rest_framework import permissions

class MyCustomPermissionClass(permissions.BasePermission):
    def has_permission(self, request, view):
        # Basically, any logic you want
        if not request.user.is_authenticated():
            raise PermissionDenied

Если вы хотите, чтобы MyCustomPermissionClass был классом разрешения по умолчанию, то вам нужно настроить его в настройках: https://www.django-rest-framework.org/api-guide/permissions/#setting-the-permission-policy. В противном случае, вам придется указать permission_classes в каждом ViewSet или APIView, которые вы используете, вот так:

class ExampleView(APIView):
    permission_classes = [MyCustomPermissionClass]

Другие примеры вы можете найти здесь: https://www.django-rest-framework.org/api-guide/permissions/#examples

Вернуться на верх