Как пометить действие DRF ViewSet как освобожденное от применения пользовательского промежуточного ПО?

Я создал Custom Django Middleware и добавил в MIDDLEWARE переменную настроек правильно.

from django.http import HttpResponseForbidden

class MyCustomMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        return self.get_response(request)

    def process_view(self, request, view_func, view_args, view_kwargs):
        # Perform some internal actions on the `request` object.
        return None

Поскольку по умолчанию это применяется ко всем DRF ViewSets, я хотел бы исключить некоторые действия, которые не нуждаются в этой проверке. Идея состоит в том, чтобы проверять флаг внутри функции process_view, вдохновляясь функцией Django CsrfViewMiddleware, которая проверяет, была ли переменная csrf_exempt установлена декоратором csrf_exempt. Поэтому я модифицировал пользовательское промежуточное ПО и создал пользовательский декоратор для явного освобождения представлений.

from functools import wraps
from django.http import HttpResponseForbidden

class MyCustomMiddleware:
    ...
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        if getattr(view_func, "some_condition", False):
            return HttpResponseForbidden("Forbidden on custom middleware")
        # Perform some internal actions on the `request` object.
        return None

def custom_middleware_exempt(view_func):

    @wraps(view_func)
    def _view_wrapper(request, *args, **kwargs):
        return view_func(request, *args, **kwargs)

    _view_wrapper.some_condition = True
    return _view_wrapper

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

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

class MyViewSet(viewsets.ViewSet):
    @action(detail=False, methods=['get'])
    @custom_middleware_exempt
    def my_action(self, request):
        return Response()

Все было хорошо, пока я не заметил, что view_func пользовательского промежуточного ПО process_view соответствует не функции действия (которая декорируется), а функции ViewSet.

Внутри декоратора: view_func = <function MyViewSet.my_action at 0x79ee9c471760>

Внутри промежуточного программного обеспечения: view_func = <function MyViewSet at 0x79ee9c49c220>

По-видимому, промежуточные модули Django применяются на уровне наборов представлений, а не на уровне действий. Как следствие, view_func не имеет установленного атрибута some_condition.

Есть ли способ украсить действие набора видов и изменить функцию уровня набора видов или альтернативный способ достичь того, что я пытаюсь сделать?

Внутри вашего промежуточного ПО вы можете просто проверить наличие флага в объекте запроса, а не непосредственно в функции представления, и на основании этого флага освободить действие.

Так что в вашем MyCustomMiddleware вы можете проверить объект запроса следующим образом:

def process_view(self, request, view_func, view_args, view_kwargs):
    if getattr(request, "custom_middleware_exempt", False):
        return None  # Skip middleware
    # whatever you want to do here
    return None

Это должно автоматически освободить вас от действий, украшенных символами @custom_middleware_exempt

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