Using Django's request after updating POST or GET attributes
If you update request.POST
or request.GET
in a view (or else where), any subsequent calls to request.REQUEST
will still return values from the old, outdated GET
and POST
dictionaries.
I came across an issue that recently left me scratching my head. Although it's quite specific, this post might help somebody in the future should they notice strange things happening when editing their request
object.
TLDR
If you update (i.e. copy and replace) request.POST
or request.GET
in a
view or elsewhere, any subsequent calls to request.REQUEST
will still return
values from the old, outdated GET
and POST
dictionaries. This can cause
difficult-to-debug problems
I was in the following situation; a view foo_view
received a request, copied and updated the request.POST
passing control over to a bar_view
. This bar_view
then read the request
information using request.REQUEST
and used the updated value to execute some code and return a response.
def bar_view(request):
country = request.REQUEST.get("country", None)
...
return render_to_response(...)
def foo_view(request):
request.POST = request.POST.copy()
request.POST.update({ 'country': 'Ireland' })
return bar_view(request)
In the above code, country
should be Ireland
but instead it was repeatedly returning None
. I imagined that after updating the POST
dictionary REQUEST
would now return values from that updated dictionary. This is not the case. The docs say of request.REQUEST
:
For convenience, a dictionary-like object that searches
POST
first, thenGET
. Inspired by PHP's$_REQUEST
. For example, ifGET = {"name": "john"}
andPOST = {"age": '34'}
,REQUEST["name"]
would be "john", andREQUEST["age"]
would be "34".
While request.POST
and request.GET
are dictionary-like QueryDict
instance, request.REQUEST
is actually a MergeDict
instance. This MergeDict
looks like a dictionary from the outside, but actually acts as a wrapper around a number of other dictionaries, and simply loops through its children looking for matches when queried.
This means that if you update request.POST
or request.GET
, any calls to request.REQUEST
after the update will still return values from the old GET
and POST
dictionaries.
What to take away:
- Avoid rendering and returning other views. I find that this only leads to trouble. I can become very difficult to visualise what is happening. Issue redirects instead where possible.
- Don't use
request.REQUEST
. It is a nice convenience for checking all passed parameters but if you are doing anything more complex be sure you understand what it does. - Be extra careful if you are editing the
request
object within a request/response cycle.