[Django]-Cannot urlencode() after storing QueryDict in session

0👍

This is very old, but as I stumbled myself because of the same issue, I want to offer a solution for those reaching this question via a search. The core issue is the default serializer Django uses for the session data: django.contrib.sessions.serializers.JSONSerializer. This serializer is not aware of keys associated with multiple values (for them, the getlist() method of QueryDict should be used), which results in only the last value for each key being used.

There are two possible solutions:

  • Either manually pickle & unpickle the request.GET or request.POST object when storing & retrieving from a session;
    • This will call the __getstate__() method of QueryDict, see also an old Django ticket.
  • Or, pickle the whole data of the session, by switching to the django.contrib.sessions.serializers.PickleSerializer.

-1👍

This is not a bug. If you take a peek at the QueryDict definition (see https://github.com/django/django/blob/master/django/http/init.py), it says explicitly that it’s immutable unless you create a copy of it.

To demonstrate this, here’s what I have in my Python shell,

>>> from django.http import QueryDict
>>> q1 = QueryDict('', mutable=False)
>>> q2 = QueryDict('', mutable=True)
>>> q1['next'] = '/a&b/'
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/kenny/Desktop/Kreybits/locker/python/lib/python2.7/site-packages/django/http/__init__.py", line 357, in __setitem__
    self._assert_mutable()
  File "/Users/kenny/Desktop/Kreybits/locker/python/lib/python2.7/site-packages/django/http/__init__.py", line 354, in _assert_mutable
    raise AttributeError("This QueryDict instance is immutable")
AttributeError: This QueryDict instance is immutable
>>> q2['next'] = '/a&b/'
>>> q2.urlencode()
'next=%2Fa%26b%2F'

The mutable argument is set to False by default, and since request.session['query_string'] = request.GET initialized it to an empty QueryDict to begin with, calling urlencode() only returns you an empty str while the request.session['query_string'] = request.GET.urlencode() works because you’re working with a QueryDict that has been initialized with the appropriate key/values.

Leave a comment