Understanding your Django session with examples
Published in · 4 min read · May 21, 2019
In my article “Managing Cookies in Django,” I discussed how cookies allow us to store data in the browser easily. Although there’s no doubt cookies are useful, they have the following problems:
- An attacker can modify contents of a cookie that could potentially break your application
- We can’t store sensitive data
- We can only store a limited amount of data in cookies. Most browsers don’t allow a cookie to store more than 4 Kb of data. Breaking data into multiple cookies causes too much overhead in each request. Further, you can’t even rely on a number of cookies allowed by the browser for each domain.
We can overcome these problems easily using sessions.
This is how sessions work:
When we use sessions, the data is not stored directly in the browser. Instead, it is stored in the server.
Django creates a unique 32-character-long random string called a session key and associates it with the session data.
The server then sends a cookie named sessionid
, containing the session key, as value to the browser.
On subsequent requests, the browser sends the cookie sessionid
to the server. Django then uses this cookie to retrieve session data and makes it accessible in your code.
To set up a session in Django, we need to add two things in our settings.py
:
‘django.contrib.sessions.middleware.SessionMiddleware'
toMIDDLEWARE
'django.contrib.sessions'
toINSTALLED_APPS
. Runpython manage.py migrate
to populate the table. The table has three columns:session_key
,session_data
, andexpire_date
.
These are automatically added when we create a new project with the startproject
command.
We know users can configure their browsers to not accept any cookie. As a result, Django provides some convenience methods to check for cookies support in the browser. The request.sessions
object provides the following three methods to check for cookies support in the browser.
set_test_cookie()
: Sets a test cookie to determine whether the user’s browser supports cookies. Due to the way cookies work, you won’t be able to test this until the user’s next page request.
test_cookie_worked()
: Returns either True
or False
, depending on whether the user’s browser accepted the test cookie. Due to the way cookies work, you’ll have to call set_test_cookie()
on a previous, separate page request.
delete_test_cookie()
: Deletes the test cookie. Use this to clean up after yourself.
Let's discuss an example.
def e_commerce_home(request): if request.session.test_cookie_worked():
request.session.delete_test_cookie()
else:
request.session.set_test_cookie()
messages.error(request, 'Please enable cookie') return render(request, 'home/home.html')
When the user browses this page, it checks whether the cookie is enabled in the browser. If not, then it sends a test cookie and shows an error message to enable cookies in the browser. If the browser accepts the cookie, then it deletes the previously sent test cookie.
A Django request
object has a session
attribute that acts like a dictionary.
# set session data
request.session[‘user_id’] = ‘20’
request.session[‘team’] = ‘Barcelona’
# read session data
request.session.get(‘user_id’) # returns ‘20’
request.session.get(‘team’) # returns ‘Barcelona’
## delete session data
del request.session[‘user_id’]
del request.session[‘user_id’]
Let’s check the ‘django.contrib.sessions.middleware.SessionMiddleware'
code to understand what it does.
- Middlewares are called before and after the view is called.
process_request(self, request)
is consumed before, andprocess_response(self, request, response)
is consumed after the view is called. process_request
checks if there is any cookie namedsessionid(default value for settings.SESSION_COOKIE_NAME)
inrequest.COOKIES
. If found, it tries to populate the session using thesession_key
column in the session database.process_response
checks whetherrequest.session
was modified or created. Then, it creates or saves the session data to the session database and adds asessionid
cookie to the response withsession_key value
. If it findsrequest.COOKIES
is not empty and all the session data is deleted, then it deletes the session row from the database and deletes the cookie from the response, which also deletes the cookie in the browser.
Let’s create a few views to understand it clearly.
def save_session_data(request):
# set new data
request.session['user_id'] = 20
request.session['team'] = 'Barcelona'
return HttpResponse("Session Data Saved")def access_session_data(request):
response = ""
if request.session.get('user_id'):
user_id = request.session.get('user_id')
response += "User Id : {0} <br>".format(user_id)
if request.session.get('team'):
team = request.session.get('team')
response += "Team : {0} <br>".format(team)if not response:
def delete_session_data(request):
return HttpResponse("No session data")
else:
return HttpResponse(response)
try:
del request.session['user_id']
del request.session['team']
except KeyError:
passreturn HttpResponse("Session Data cleared")
Here’s what happens when the save_session_data()
view is called.
'django.contrib.sessions.middleware.SessionMiddleware'
middleware creates a new random session key and associates the session data with it.'django.contrib.sessions.middleware.SessionMiddleware'
uses the'django.contrib.sessions'
app to store the session data in the database.- At last, a cookie named
sessionid
with a random value (session key), generated in step 1, is sent to the browser. - From now on, the browser will send this
sessionid
cookie with every request to the server, allowing Python code to access session data in views usingrequest.session
.
When access_session_data
is called after save_session_data
, the sessionid
cookie is available in request.COOKIES
. The middleware’s process_request
uses this sessionid
to populate the session for this request.
In delete_session_data
, we’re deleting all of the session data. The middleware identifies there’s no session data for this session, so it deletes the session row and also deletes response cookies which deletes the cookie in the browser.
By default, Django only saves to the session database when the session has been modified — that is, if any of its dictionary values have been assigned or deleted:
# Session is modified.
request.session['foo'] = 'bar'# Session is modified.
del request.session['foo']
# Session is modified.
request.session['foo'] = {}
Another important point worth mentioning here is Django sends the session cookie to the browser only when the session data is modified. In the process, it also updates the cookie expiry time.
Session database has three columns:
session_key
: To store the unique random session ID (or SID)
session_data
: Django stores the session data in the encoded format. To get the raw data, use theget_decoded()
method of the session object.
expire_date
: The expiration date of the session cookie