The movie website we created in the previous articles allows users to browse movies and directors. While the content is dynamically generated from the database, every user will essentially have access to the same pages and types of information when they use the site.

In a “real” production site you may wish to provide individual users with a customized experience, based on their previous use of the site, preferences, etc.

For example, you could hide warning messages that the user has previously acknowledged next time they visit the site, or store and respect their preferences (e.g. the number of search results they want displayed on each page).

The session framework lets you implement this sort of behaviour, allowing you to store and retrieve arbitrary data on a per-site-visitor basis.

What are sessions?

All communication between web browsers and servers is via the HTTP protocol, which is stateless. The fact that the protocol is stateless means that messages between the client and server are completely independent of each other— there is no notion of “sequence” or behaviour based on previous messages. As a result, if you want to have a site that keeps track of the ongoing relationships with a client, you need to implement that yourself.

Sessions are the mechanism used by Django (and most of the Internet) for keeping track of the “state” between the site and a particular browser. Sessions allow you to store arbitrary data per browser, and have this data available to the site whenever the browser connects. Individual data items associated with the session are then referenced by a “key”, which is used both to store and retrieve the data.

Django uses a cookie containing a special session idto identify each browser and its associated session with the site. The actual session data is stored in the site database by default (this is more secure than storing the data in a cookie, where they are more vulnerable to malicious users).

To enable session functionality, do the following:

  • Edit the MIDDLEWARE setting and make sure it contains 'django.contrib.sessions.middleware.SessionMiddleware'. The default settings.py created by django-admin startproject has SessionMiddleware activated.

If you don’t want to use sessions, you might as well remove the SessionMiddleware line from MIDDLEWARE and 'django.contrib.sessions' from your INSTALLED_APPS. It’ll save you a small bit of overhead.

You can configure Django to store the session data in other places (cache, files, “secure” cookies), but the default location is a good and relatively secure option.

The built-in session engine are:

  • django.contrib.sessions (database-backed sessions)
  • django.contrib.sessions.backends.cache (simple caching session)
  • django.contrib.sessions.backends.cached_db (persistent caching sessions)
  • django.contrib.sessions.backends.file(file-based sessions)
  • django.contrib.sessions.backends.signed_cookies (cookie-based sessions)

Settings for django.contrib.sessions:

  • SESSION_COOKIE_AGE:Default: 1209600 (2 weeks, in seconds)。
  • SESSION_COOKIE_DOMAIN:Default: None, The domain to use for session cookies.
  • SESSION_COOKIE_SECURE:Default: False. Whether to use a secure cookie for the session cookie. If this is set to True, the cookie will be marked as “secure”, which means browsers may ensure that the cookie is only sent under an HTTPS connection.
  • SESSION_COOKIE_HTTPONLY: Default: True. Whether to use HttpOnly flag on the session cookie. If this is set to True, client-side JavaScript will not be able to access the session cookie.
  • SESSION_EXPIRE_AT_BROWSER_CLOSE:Default: False. Whether to expire the session when the user closes their browser.
  • SESSION_SAVE_EVERY_REQUEST:布尔值,默认为False,设置为True表示每次HTTP请求都会更新session,其中的过期时间相关设置也会一起更新。

Using sessions

You can access the session attribute in the view from the request parameter (an HttpRequest passed in as the first argument to the view). This session attribute represents the specific connection to the current user (or to be more precise, the connection to the current browser, as identified by the session id in the browser’s cookie for this site).

The code fragments below show how you can get, set, and delete some data with the key “my_car”, associated with the current session (browser).

1
2
3
4
5
6
7
8
9
10
11
## Get a session value by its key (e.g. 'my_car'), raising a KeyError if the key is not present
my_car = request.session['my_car']

## Get a session value, setting a default if it is not present
my_car = request.session.get('my_car', 'mini')

## Set a session value
request.session['my_car'] = 'mini'

## Delete a session value
del request.session['my_car']

Saving session data

By default, Django only saves to the session database and sends the session cookie to the client when the session has been modified (assigned) or deleted. For example:

1
2
# This is detected as an update to the session, so session data is saved.
request.session['my_car'] = 'mini'

If you’re updating some information within session data, then Django will not recognise that you’ve made a change to the session and save the data. In this case you will need to explicitly mark the session as having been modified.

1
2
3
4
5
# Session object not directly modified, only data within the session. Session changes not saved!
request.session['my_car']['wheels'] = 'alloy'

# Set session as modified to force data updates/cookie to be saved.
request.session.modified = True

Note: You can change the behavior so the site will update the database/send cookie on every request by adding SESSION_SAVE_EVERY_REQUEST = True into your project settings.

Simple example — getting visit counts

As a simple real-world example we’ll update our movie site to tell the current user how many times they have visited.

Open views.py, and make the changes shown in bold below.

1
2
3
4
5
6
7
8
9
10
11
def movie_list(request, tag_slug=None):
# Number of visits to this view, as counted in the session variable.
num_visits = request.session.get('num_visits', 0)
request.session['num_visits'] = num_visits + 1
...
context = {
...
'num_visits': num_visits,
}

return render(request, 'movie/movie_list.html', context)

Here we first get the value of the 'num_visits' session key, setting the value to 0 if it has not previously been set. Each time a request is received, we then increment the value and store it back in the session (for the next time the user visits the page). The num_visits variable is then passed to the template in our context variable.

REFERENCES