I’ve created a Custom Django Middleware and added to the MIDDLEWARE
settings variable correctly.
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
Since this is applied to all DRF ViewSets by default, I would like to exempt some actions that don’t need this check. The idea would be to check a flag inside the process_view
function taking inspiration from the Django CsrfViewMiddleware
which checks if the csrf_exempt
variable has been set by the csrf_exempt
decorator. So I modified the custom middleware and created a custom decorator to exempt views explicitly.
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
Having this I do something like this and it correctly enters the custom decorator before going inside the Django middleware.
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()
So far so good until I noticed that the view_func
of the custom middleware process_view
doesn’t correspond to the action function (which is being decorated) but to the ViewSet function.
Inside the decorator: view_func = <function MyViewSet.my_action at 0x79ee9c471760>
Inside the middleware: view_func = <function MyViewSet at 0x79ee9c49c220>
Apparently, Django middlewares are applied at viewset level instead of action level. As a consequence view_func
doesn’t have the some_condition
attribute set.
Is there a way to decorate a viewset action and change the viewset level function or an alternative way to achieve what I’m trying to do?