Home > database >  Why is the Middleware not processed on 404 page in Django?
Why is the Middleware not processed on 404 page in Django?

Time:07-22

So I've set up a path in my URL config:

path(
    "kitten/",
    views.Kitten.as_view(),
    name="kitten",
),

and a handler for missing URLs to the same view.

handler404 = views.Kitten.as_view()

I have some middleware which sets some context data:

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

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

    def process_template_response(self, request, response):
        response.context_data["hasCookie"] = False        
        return response

and the view is very straightforward,

class Kitten(TemplateView):
    template_name = "kitten.html"

and the template prints the value of hasCookie.

Visiting kitten/ correctly displays the value of hasCookie, but visiting a URL that doesn't exist, displays no value for hasCookie (whilst showing the right template)

Adding debugging statements to the middleware, it becomes apparent that whilst process_view, process_template_response and process_exception are called for kitten/, none of these are called for URLs that don't exist, so no code is called to set the value of hasCookie. (__init__ is called regardless at app startup)

Why does it not call the middleware when the URL is not found in the URLconf?

CodePudding user response:

Your middleware does get called but not its process_template_response method since Django calls the render function on the response from the exception handler making it not a TemplateResponse object anymore. This can be seen in the code [GitHub] for the response_for_exception function:

# Force a TemplateResponse to be rendered.
if not getattr(response, "is_rendered", True) and callable(
    getattr(response, "render", None)
):
    response = response.render()

This is because response_for_exception is called by convert_exception_to_response which needs to do ensure the response is rendered since it wraps both the first and the last middleware in the chain.

It seems you are using the middleware to add values to your context, which is not the best place to do this. You should instead write a custom context processor which will be called consistently.

  • Related