What are Session and Cookie?
In web development, sessions and cookies are fundamental concepts critical in managing user interactions and maintaining state across multiple requests. Understanding these concepts is essential for building robust web applications with frameworks like Django.
A session is a way to store information about a user across multiple requests. Since HTTP is a stateless protocol, each request from a user is independent of others. Without sessions, a web server could not recognize if consecutive requests come from the same user.
Sessions solve this problem by allowing data to persist between different requests. When a user visits a web application, a unique session ID is created and stored on the server. This session ID is then sent to the client, typically stored in a cookie, and returned to the server with each subsequent request. The server can retrieve the user's session data using this session ID, maintaining continuity and enabling features like user authentication, shopping carts, and personalized experiences.
There is another thing you must know along with the session. It is called a cookie. A cookie is a small piece of data stored on the client side by the web browser. Cookies are used to remember information about the user, such as preferences, login status, and tracking information. When a user visits a website, the server can send a cookie to the browser, which stores it and sends it back with each subsequent request to the same server. Cookies have various attributes like expiration time, domain, and path, which determine their lifespan and scope of availability. They can be used for multiple purposes, including session management, personalization, and tracking user behavior.
Django Session Middleware
Sessions are a powerful and flexible way to manage user data across requests in Django. The framework abstracts away the complexities of session management, providing a simple and secure API for developers. You can use session features by adding built-in middleware that Django has provided.
Here’s the step-by-step guide to using the Django session.
1. Configuration
Before using sessions, ensure that the django.contrib.sessions app is included in the INSTALLED_APPS setting in your settings.py file. Additionally, add SessionMiddleware to the MIDDLEWARE setting. This middleware is responsible for managing session data for each request and response.
2. Backend setup
Django supports several session backends, such as database-backed, cached, file-based, and cookie-based. By default, Django uses the database backend. You can specify a different backend by setting the SESSION_ENGINE setting in your settings.py.
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
The default variable is db, which is specified in the global_settings.py in the Django framework.
If you specify the SESSION_ENGINE value in settings.py, Django treats it as a module path. When SessionMiddleware is initiated, it imports the module from that path.
There are other types of engines that you can use for the Django session. Here’s the Django framework codebase, and you can find the cache, cached_db, file, and signed_cookies as the provided engine for the Django session backend.
If you want to create your own session engine, you can inherit the AbstractBaseSession class from the Django library. Here’s an example of a custom session in the official Django document. As you might notice, you should specify the custom path to SESSION_ENGINE because Django should load it when the middleware is initiated.
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
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
3. Session ID Creation
When a user visits your website, Django generates a unique session ID if it doesn't already exist. This session ID is a long, random string that serves as a key to store and retrieve session data.
It is not created in the processing request. It is generated when the response is processed. When processing a request, it only retrieves the session_key from the cookie that the client sends. The cookie name is defined in the SESSION_COOKIE_NAME setting, and of course, you can change the cookie name by specifying SESSION_COOKIE_NAME in settings.py. The default value is “sessionid”.
while processing the response, it calls request.session.save() function when the session data is modified.
If the first traffic comes from the browser, it does not have a session_key. So, SessionStore creates a new random string when it saves the session data. Here’s the saving logic of the database backend.
When the self.create() function is called, the _get_new_session_key() function is called as well. This function generates a new session key with a random string.
4. Storing Session ID in a Cookie
The session ID is sent to the client's browser in a sessionid cookie. If you change the SESSION_COOKIE_NAME in settings.py, another name will be used. Each subsequent request sends This cookie to the server, allowing Django to identify the session and retrieve the associated data.
Here’s an example of changing the session cookie name. I manually added the SESSION_COOKIE_NAME value in settings.py and checked the cookie name in the browser.
5. Session Data Storage
Depending on your configured session backend, session data is stored on the server side. For the default database backend, session data is stored in the django_session table. Each session has a corresponding record in this table, which maps the session ID to the serialized session data.
Here’s the model class that Django uses internally to store the session data in the database. As you can see, the table's name is hard-coded as “django_session.” So you can quickly check your database and find the session records with this name.
6. Accessing and Retrieving Session Data
When the client makes a subsequent request, the sessionid cookie is sent along with the request. Django retrieves the session ID from the cookie and looks up the corresponding session data from the session backend.
# Example of retrieving a session variable
user_id = request.session.get('count')
If the data is already in memory, it will return right away. But if it does not exist, it will load the data from the database and check if there is a key. Basically, Django creates session data using the process_request function. This means that whenever you send a request to the Django server, there is no data in the memory. It’s because the SessionStore instance is created at every request.
I printed the session’s __dict__ variable to check if there is data that I want to access. I wrote the program that every time I access the page, I increase the session[‘count’] by 1.
Here’s the result. Before accessing the “count” variable, there was no data inside. After I access it once, it has count data in _session_cache. If you access it next time in the same request, it will get data from memory.
Here’s the function called when you find data with a key. If no _session_cache attribute exists, it loads data from the backend and saves it to _session_cache. This can save the traffic to the session backend, which does not use session data at all.
When you change the data while handling the request, it will only change the memory. Changes are automatically saved at the end of the request, ensuring the session data is kept current.
In summary, Django's session framework provides a powerful and flexible way to manage user data. The framework's secure and abstracted approach simplifies session management, allowing developers to focus on building feature-rich applications. Even though you can use it without knowing the detailed implementation of the session store, debugging the application when it is related to the session would be better.
If you liked this post, please subscribe to my newsletter and restack for others to find me!