Question
Using set_test_cookie in a django view fails to actually set a test cookie and I can’t figure out why.
Steps to Reproduce
The actual project is much more complex than this, however, the error is reproducible in a near empty project.
Shell
$ virtualenv venv
$ source venv/bin/activate
(venv)$ pip install django
(venv)$ django-admin.py startproject hellodjango .
(venv)$ python manage.py startapp polls
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'database.db', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
urls.py
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
url(r'^login/$', 'hellodjango.polls.views.login'),
)
polls/views.py
from django.shortcuts import render_to_response
from django.http import HttpResponse
def login(request):
if request.method == 'POST':
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponse("You're logged in.")
else:
return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie()
return HttpResponse("Look ma, no cookies!")
Shell
(venv)$python manage.py runserver
Browser
Go to localhost:8000/login/ and notice that your get request does not show a response cookie with the name testcookie and the value worked as per the set_test_cookie source.
Actually, it works! You might want to visit your website with cookies disabled and see for yourself.
Anyway, here’s the explanation:
If you look at the source for
set_test_cookie, you’ll notice that it actually sets a variable in the current session, not a cookie or anything (at least, not directly).Here’s how it works:
set_test_cookie, a key ofTEST_COOKIE_NAMEand of valueTEST_COOKIE_VALUEis added to your current session.__setitem__method), so a sessionid (1) cookie will be sent (2)POSTdata in your next request, django checks whether the keyTEST_COOKIE_NAMEhappens to be in your session data and has the right value.If it does, it means we were able to retrieve your session from your request, so that the sessionid cookie we used to identify you was sent back (lest we wouldn’t have been able to retrieve your session), so you must support cookies.
Hope this makes things clearer to you; if it doesn’t, I think you should look into the details of how HTTP works.
Notes
(1) Or whatever the
SESSION_COOKIE_NAMEsetting sets.(2) Actually, a sessionid cookie will be sent even if the session was not altered if the
SESSION_SAVE_EVERY_REQUESTsetting is true