Как применить промежуточное ПО Django везде, кроме единственного пути?

Я использую Python 3.9 с Django 3. Я определил это промежуточное ПО ...

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'directory.middleware.extend_token_response.ExtendTokenResponse'
]

Однако я не хочу, чтобы промежуточное ПО применялось к определенному URL. Я жестко закодировал это в промежуточном ПО так

class ExtendTokenResponse:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        response = self.get_response(request)
        if request.path != '/' + LOGOUT_PATH:
            # Code to be executed for each request before
            # the view (and later middleware) are called.
            is_expired = True
            try:
                token = request.auth
                print("req path: %s" % request.path)
                is_expired = is_token_expired(token) if token else True
            except Exception as err:
                print(err)
            if not is_expired:

но это кажется немного небрежным, и я думаю, что промежуточное ПО поставляется с чем-то из коробки для настройки, что не нужно применять к моему пути "/logout". Есть ли более элегантный способ настроить это?

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

Однако, если вы хотите пометить определенные представления, чтобы исключить их из обработки, вы можете использовать декораторы так же, как это делает Django с декоратором csrf_exempt.

from functools import wraps

def token_response_exempt(view_func):
    # Set an attribute on the function to mark it as exempt
    def wrapped_view(*args, **kwargs):
        return view_func(*args, **kwargs)

    wrapped_view.token_response_exempt = True
    return wraps(view_func)(wrapped_view)

# your middleware
class ExtendTokenResponse:
    def process_view(request, view_func, view_args, view_kwargs):
         if getattr(view_func, "token_response_exempt", False):
            return None
         # do your middleware stuff here...
         # ....

А затем вы можете использовать декоратор, как показано ниже:

# urls.py

urlpatterns = [
    path('logout/', token_response_exempt(LogOutView.as_view())),
]

По поводу вашего случая у меня есть 2 рекомендации:

Метод 1: использовать process_view и определить список func, которые будут исключены со структурой "app.module.func" и проверить пропустить в process_view

# In settings.py
EXCLUDE_FROM_MY_MIDDLEWARE =set({'custom_app.views.About'})

# In middlewares.py
class ExtendTokenResponse:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        logger.info(f'request hit request {request}')
        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    def process_view(self, request, view_func, view_args, view_kwargs):

        view_function = '.'.join((view_func.__module__, view_func.__name__))
        exclusion_set=getattr(settings,'EXCLUDE_FROM_MY_MIDDLEWARE',set() )
        if view_function in exclusion_set:
            return None

Метод 2: Используйте decorator_from_middleware и применяйте промежуточное ПО к каждой функции, нуждающейся в нем.

from django.utils.decorators import decorator_from_middleware
# with function view
@decorator_from_middleware(ExtendTokenResponse)
def view_function(request):
...
#with class view
class SimpleMiddlewareMixin:
    @decorator_from_middleware(ExtendTokenResponse) 
    def dispatch(*args, **kwargs):
        return super().dispatch(*args, **kwargs)

class MyClassBasedView(SimpleMiddlewareMixin, ListView):

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