Strange Persistence in request query parameters between Django Views

I have a view that anticipates optional url queries

class MyView(LoginRequiredMixin, FormView):
    def get(self, request, *args, **kwargs):
        """Handle GET requests: instantiate a blank version of the form."""
        
        param = request.GET.get("param")
        if param == "showme":
            self.extra_context["showme"] = {"some text on a message box"} # this message
        return super().get(request, *args, **kwargs)

Lets say this view is getting called by /app/page?param=showme

The above works fine when the query is present. However, I find that message persists when the view is called without a query (e.g. /app/page).

If I called the view without the query to begin with … it works fine (no message shows). Then I call the view with the query, the message shows as expected. If I call the view henceforth without the query, the message persists … yet the view is not getting the queries.

Why is this happening?

I would try some low tech debugging: put different print() statements in the get() method, outside and inside the if statement. When you visit the page and the unexpected behaviour happens, do both those statements output to your logs?

I suspect something’s being cached somewhere - if so then you won’t see the output in your logs.

I assume that we’re not seeing all the code. Where is self.extra_context initialized? It’s likely that extra_context is persisting on self between requests.

def get(self, request, *args, **kwargs):
        """Handle GET requests: instantiate a blank version of the form."""
        
        param = request.GET.get("param")
        self.extra_context = {}
        if param == "showme":
            self.extra_context["showme"] = {"some text on a message box"} # this message
        return super().get(request, *args, **kwargs)

Another place to initialize it is inside the setup method.

Well, if you’re not cleaning up “extra_context” that might be the one who is causing this “pollution”. I believe that how class-based views work. Normally django class based views uses method calls instead of instance parameters to pass data around. Since your view inherits from FormView, you can use the get_context_data method. This can be rewritten as follows:

class MyView(LoginRequiredMixin, FormView):
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        param = self.request.GET.get("param")
        if param == "showme":
            context["showme"] = {"some text on a message box"} # this message
        return context

When working with class based views, this website is really helpful: ccbv.co.uk

To clarify what massover said:

class Foo(FormView):
    extra_context = {}  # This will be ONE dict per server process

which is not what you want.

That made sense. That put the whole thing in perspective.