A Complete Guide to Using Sessions in Django and Configuring Session Storage Engines

This article explains how Django sessions work, how to enable session support, how to configure different session storage engines including database, cache, file-based, and cookie-based sessions, and highlights important security and performance considerations when choosing the right session backend.

Django SessionSESSION_ENGINEcached_db

~12 min read • Updated Mar 14, 2026

Introduction

Django provides a powerful session framework that allows you to store and retrieve arbitrary data on a per-user basis. Session data is stored on the server, while the client only receives a session ID in a cookie. This design improves security and flexibility when managing user state.


Enabling Sessions

Sessions are enabled through SessionMiddleware. To activate session support, ensure the following middleware is included in your settings:


MIDDLEWARE = [
    ...
    "django.contrib.sessions.middleware.SessionMiddleware",
    ...
]

If you do not need sessions, remove this middleware and also remove 'django.contrib.sessions' from INSTALLED_APPS to reduce overhead.


Configuring the Session Engine

Django uses a database-backed session engine by default. However, you can configure sessions to use the filesystem, cache, or cookies depending on your performance and security needs.


Using Database-Backed Sessions

To use database sessions:

  • Add 'django.contrib.sessions' to INSTALLED_APPS.
  • Run manage.py migrate to create the session table.

This method is reliable and suitable for most applications.


Using Cached Sessions

For improved performance, you can store session data in Django’s cache system. Before using this backend, ensure your cache is properly configured.


Important Notes

  • Use only Memcached or Redis for cache-based sessions.
  • The local-memory cache backend is not persistent and not safe for multi-process environments.

1. Cached Database Backend (cached_db)

This backend writes session data to both the database and the cache:


SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"

Reads are served from the cache, falling back to the database if needed.


2. Cache-Only Backend (cache)

This backend stores session data only in the cache:


SESSION_ENGINE = "django.contrib.sessions.backends.cache"

This is faster but risky because session data is lost if the cache is cleared or restarted.


If using a persistent cache like Redis, this backend can be safe, but cached_db is still recommended for production stability.


Using File-Based Sessions

To store session data in files:


SESSION_ENGINE = "django.contrib.sessions.backends.file"

To specify a custom directory:


SESSION_FILE_PATH = "/path/to/sessions"

Ensure your web server has read/write permissions for this directory.


Using Cookie-Based Sessions

To store session data directly in cookies:


SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"

Session data is signed using SECRET_KEY but not encrypted.


Security Considerations

  • Data is readable by the client but cannot be modified without invalidation.
  • Cookies have a size limit of ~4096 bytes.
  • Cookie-based sessions do not invalidate on logout, making them vulnerable to replay attacks.

To prevent JavaScript access:


SESSION_COOKIE_HTTPONLY = True

Performance Considerations

Large cookies slow down requests and responses. Cookie-based sessions should be used only for small-scale applications or specific use cases.


Conclusion

Django offers multiple session storage backends, each with different trade-offs in performance, security, and persistence. Choosing the right session engine depends on your application’s requirements. For most production environments, database or cached_db provides the best balance of reliability and performance.


Introduction

When SessionMiddleware is enabled, every HttpRequest object includes a session attribute. This attribute behaves like a dictionary and allows you to store and retrieve data for each individual user. You can modify request.session at any point during the view execution.


The SessionBase Class

All session objects inherit from SessionBase. This class provides a dictionary-like API with both synchronous and asynchronous methods.


Dictionary-Like Methods

Reading and Writing Values

  • request.session['fav_color'] → read a value
  • request.session['fav_color'] = 'blue' → write a value
  • del request.session['fav_color'] → delete a value
  • 'fav_color' in request.session → check existence

Using get() and aget()

fav_color = request.session.get('fav_color', 'red')
fav_color = await request.session.aget('fav_color', 'red')

Updating Multiple Keys

request.session.update({'fav_color': 'red'})
await request.session.aupdate({'fav_color': 'red'})

Using pop() and apop()

fav_color = request.session.pop('fav_color', 'blue')
fav_color = await request.session.apop('fav_color', 'blue')

Iterating Over Keys and Values

  • keys() / akeys()
  • values() / avalues()
  • items() / aitems()

Other Dictionary Helpers

  • setdefault() / asetdefault()
  • clear()

Session Management Methods

flush() / aflush()

Deletes all session data and removes the session cookie. This ensures old session data cannot be reused. Django’s logout() function uses this method.


is_empty()

Returns True if the session contains no keys.


Test Cookies

These methods help determine whether the user’s browser supports cookies.


  • set_test_cookie() / aset_test_cookie()
  • test_cookie_worked() / atest_cookie_worked()
  • delete_test_cookie() / adelete_test_cookie()

Because cookies are only available on the next request, these methods must be used across two separate page loads.


Session Expiration

set_expiry(value) / aset_expiry(value)

Controls when the session expires. Accepted values:

  • Integer: expire after N seconds (e.g., set_expiry(300) → 5 minutes)
  • datetime / timedelta: expire at a specific time
  • 0: expire when the browser closes
  • None: use global session expiry settings

Note: Reading a session does not count as activity. Only modifications reset the expiration timer.


get_expiry_age() / aget_expiry_age()

Returns the number of seconds until the session expires.


get_expiry_date() / aget_expiry_date()

Returns the exact date/time when the session will expire.


get_expire_at_browser_close()

Returns True if the session is set to expire when the browser closes.


Session Cleanup

clear_expired() / aclear_expired()

Removes expired sessions from the session store. Django’s clearsessions management command calls this method.


Security: Preventing Session Fixation

cycle_key() / acycle_key()

Creates a new session key while keeping the existing session data. Django calls this during login to prevent session fixation attacks.


Conclusion

Django’s session system provides a rich API for managing user-specific data securely and efficiently. With both synchronous and asynchronous methods, fine-grained expiration control, test cookies, and security features like cycle_key() and flush(), developers can build robust session-dependent features with confidence.


Introduction

Django stores session data using a serialization system. By default, Django uses JSON to serialize session values, ensuring safety, portability, and compatibility with different session backends. Developers can customize this behavior using the SESSION_SERIALIZER setting.


Default JSON Serialization

The default serializer is JSONSerializer, which supports only basic data types. JSON is recommended, especially when using the cookie backend, because it avoids the security risks associated with other serialization formats.


Security Risks of Using pickle

If you use pickle for session serialization and your SECRET_KEY is leaked, an attacker can craft malicious data that executes arbitrary code when unpickled. This creates a severe remote code execution vulnerability.


Bundled Serializers

JSONSerializer

This serializer wraps Django’s signing-based JSON serializer. It supports only string keys and basic JSON-compatible values.


Example of Key Conversion

# initial assignment
request.session[0] = "bar"

# after serialization/deserialization
request.session[0]      # KeyError
request.session["0"]    # 'bar'

Non-UTF8 bytes also cannot be stored because JSON cannot encode them.


Writing a Custom Serializer

If you need to store complex types such as datetime or Decimal, you must write a custom serializer or convert values to JSON-safe types before storing them.


A custom serializer must implement:

  • dumps(self, obj)
  • loads(self, data)

Encoding is usually simple, but decoding can be fragile because values may be misinterpreted as other types.


Session Object Guidelines

  • Use normal Python strings as session keys.
  • Keys beginning with _ are reserved for Django internals.
  • Do not replace request.session with a new object.
  • Use request.session like a dictionary.

Examples of Session Usage

Preventing Duplicate Comments

def post_comment(request, new_comment):
    if request.session.get("has_commented", False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session["has_commented"] = True
    return HttpResponse("Thanks for your comment!")

Simple Login Example

def login(request):
    m = Member.objects.get(username=request.POST["username"])
    if m.check_password(request.POST["password"]):
        request.session["member_id"] = m.id
        return HttpResponse("You're logged in.")
    return HttpResponse("Your username and password didn't match.")

Simple Logout Example

def logout(request):
    try:
        del request.session["member_id"]
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

Setting Test Cookies

Django provides helper methods to test whether the user’s browser accepts cookies. You must call set_test_cookie() in one request and test_cookie_worked() in the next.


Example

def login(request):
    if request.method == "POST":
        if request.session.test_cookie_worked():
            request.session.delete_test_cookie()
            return HttpResponse("You're logged in.")
        return HttpResponse("Please enable cookies and try again.")
    request.session.set_test_cookie()
    return render(request, "foo/login_form.html")

Using Sessions Outside Views

You can manipulate session data outside views using SessionStore. It is recommended to import it dynamically based on SESSION_ENGINE.


Example: Creating and Accessing a Session

from importlib import import_module
from django.conf import settings

SessionStore = import_module(settings.SESSION_ENGINE).SessionStore

s = SessionStore()
s["last_login"] = 1376587691
s.create()
key = s.session_key

s = SessionStore(session_key=key)
s["last_login"]

Accessing Session Model Directly

from django.contrib.sessions.models import Session

s = Session.objects.get(pk=key)
data = s.get_decoded()

When Sessions Are Saved

Django saves session data only when it has been modified. Assigning or deleting keys marks the session as modified, but modifying nested data does not.


Example

request.session["foo"] = "bar"      # modified
del request.session["foo"]          # modified
request.session["foo"] = {}         # modified

request.session["foo"]["bar"] = 1   # NOT modified
request.session.modified = True     # force save

Browser-Length vs Persistent Sessions

The SESSION_EXPIRE_AT_BROWSER_CLOSE setting controls whether sessions expire when the browser closes. This can be overridden per session using set_expiry().


Some browsers restore sessions after restart, which may affect this behavior.


Conclusion

Session serialization is a critical part of Django’s session framework. Understanding JSON limitations, avoiding insecure serializers like pickle, following best practices for session keys, and knowing how to manage sessions both inside and outside views ensures secure and reliable session handling in Django applications.


Introduction

In the Django framework, managing Session data is essential for maintaining user state. However, without regular cleanup, the Session Store can grow indefinitely, increasing database size or file count. This article explores how to clear expired sessions, important session settings, security considerations, and how to extend the Session Engine.


Why the Session Store Needs Clearing

When a user logs in, Django creates a record in the django_session table. If the user logs out manually, the record is deleted. But if the user never logs out, the record remains indefinitely. The same issue occurs with the File Backend, where session files accumulate in the temporary directory.


The Core Problem

  • Expired sessions are not removed automatically
  • Database or file storage grows over time
  • Potential performance degradation

Clearing Sessions with the clearsessions Command

Django provides the clearsessions management command to remove expired session records. This command should be executed regularly, typically via a cron job.


python manage.py clearsessions

This command deletes expired rows from django_session, keeping storage clean and efficient.


Backends That Do Not Require Manual Cleanup

  • Cache Backend: Automatically removes stale data.
  • Cookie Backend: Stores session data in the user's browser.

Important Session-Related Settings

Django provides several settings to control session behavior:

  • SESSION_ENGINE
  • SESSION_COOKIE_AGE
  • SESSION_EXPIRE_AT_BROWSER_CLOSE
  • SESSION_SAVE_EVERY_REQUEST
  • SESSION_FILE_PATH
  • SESSION_SERIALIZER

Session Security

One major threat is Session Fixation. This attack occurs when an untrusted subdomain can set a session cookie for the entire domain. Incorrectly configuring SESSION_COOKIE_DOMAIN can expose your site to this vulnerability.


Example Attack Scenario

If good.example.com sets SESSION_COOKIE_DOMAIN to example.com, a malicious subdomain like bad.example.com could inject a crafted session cookie.


Technical Details of SessionStore

Django uses the SessionStore class internally to manage session data. The class is loaded from the module specified by SESSION_ENGINE.


Key SessionStore Methods

  • exists()
  • create()
  • save()
  • delete()
  • load()
  • clear_expired()

Async Variants

  • aexists()
  • acreate()
  • asave()
  • adelete()
  • aload()
  • aclear_expired()

Building a Custom Session Engine

To create a custom session engine, you can inherit from SessionBase or existing store classes. For database-backed engines, you often need a custom model as well.


Example Custom Session Model

from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.contrib.sessions.base_session import AbstractBaseSession
from django.db import models

class CustomSession(AbstractBaseSession):
    account_id = models.IntegerField(null=True, db_index=True)

    @classmethod
    def get_session_store_class(cls):
        return SessionStore

Example Custom SessionStore

class SessionStore(DBStore):
    @classmethod
    def get_model_class(cls):
        return CustomSession

    def create_model_instance(self, data):
        obj = super().create_model_instance(data)
        try:
            account_id = int(data.get("_auth_user_id"))
        except (ValueError, TypeError):
            account_id = None
        obj.account_id = account_id
        return obj

Session IDs in URLs

Unlike some platforms such as PHP, Django never places Session IDs in URLs. This prevents attacks involving the Referer Header.


Conclusion

Regularly clearing expired sessions is essential when using the Database Backend or File Backend. By scheduling clearsessions, configuring session settings properly, and following security best practices, you can maintain both performance and safety. Django also allows building custom session engines for advanced use cases.


Written & researched by Dr. Shahin Siami