~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'toINSTALLED_APPS. - Run
manage.py migrateto 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
MemcachedorRedisfor 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 = TruePerformance 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 valuerequest.session['fav_color'] = 'blue'→ write a valuedel 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.sessionwith a new object. - Use
request.sessionlike 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 saveBrowser-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_ENGINESESSION_COOKIE_AGESESSION_EXPIRE_AT_BROWSER_CLOSESESSION_SAVE_EVERY_REQUESTSESSION_FILE_PATHSESSION_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