Проблема с декоратором Django и промежуточным ПО
Мой декоратор выглядит следующим образом
def require_feature(feature_name):
def decorator(view_func):
print(f"process_view - view_func: {view_func}") # Debugging
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
return view_func(request, *args, **kwargs)
_wrapped_view.required_feature = feature_name
return _wrapped_view
return decorator
а промежуточное программное обеспечение выглядит следующим образом
class EntitlementMiddleware(MiddlewareMixin):
def __init__(self, get_response) -> None:
self.get_response = get_response
def __call__(self, request) -> Any:
if request.user.is_authenticated:
request.user.features = get_user_features(request.user)
else:
request.user.features = []
return self.get_response(request)
def process_view(self, request, view_func, view_args, view_kwargs):
print(f"process_view - view_func: {view_func}") # Debugging
required_feature = getattr(view_func, "required_feature", None)
if required_feature and not request.user.features.filter(name=required_feature):
raise PermissionDenied("You do not have access to this feature")
return None # if none is returned then view is called normally
def process_response(self, request, response):
return response
и вот как я использую его в своем наборе представлений
class MyViewSet(ValidatePkMixin, viewsets.ViewSet):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
queryset = My.objects.all()
@method_decorator(require_feature("Basic"))
def list(self, request):
pass
декоратор устанавливает required_feature при запуске сервера. промежуточное ПО вызывается, когда я делаю вызов /get, но это
required_feature = getattr(view_func, "required_feature", None)
возвращает None
что я здесь упускаю?
Вы проверяете из middleware функцию(метод) dispatch
, которая будет вызываться из middleware. А вы оформляете совершенно другую функцию(метод) list
.
В Django при работе с Generic CBVs или ViewSets запрос проходит через middlewares, а через Class.as_view()
возвращается запрос-диспетчер.
Для обоих вариантов - для Generic CBVs и для ViewSets - это:
class View:
...
def dispatch(self, request, *args, **kwargs):
return handler # exactly here will be called your cls.list
...