Skip to content

Django - Cookies Handling

HTTP is a stateless protocol, meaning each request is independent. Cookies are small pieces of data that websites store on a user’s browser. They allow web applications to remember information about the user across multiple requests, essentially adding state.

Common uses for cookies include:

  • Session management (tracking logged-in users). Django’s session framework often handles this automatically.
  • Personalization (remembering user preferences like themes or language).
  • Tracking (analyzing user behavior, though privacy concerns are significant here).

Important Considerations:

  • Client-Side Storage: Cookies are stored on the user’s computer, making them potentially insecure for sensitive data.
  • User Control: Users can configure their browsers to block cookies or delete them.
  • Size Limits: Browsers impose limits on the number and size of cookies per domain.
  • Security: Use the HttpOnly and Secure flags, and SameSite attribute appropriately to mitigate risks like Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF).
  • Privacy Regulations: Be mindful of regulations like GDPR and CCPA regarding cookie usage and consent.

Cookies are set on the HttpResponse object before it’s returned from the view. You use the response.set_cookie() method.

Let’s modify a hypothetical login view to set a cookie remembering the user’s theme preference.

from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import LoginForm # Assuming you have a LoginForm defined
import datetime
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
# Simulate successful login
# ... (authentication logic would go here)
# Create a response object (e.g., redirect to dashboard)
response = redirect('dashboard') # Assuming 'dashboard' is a named URL
# Set a cookie for theme preference
theme = request.POST.get('theme', 'light') # Get theme from form or default
response.set_cookie(
key='user_theme',
value=theme,
max_age=60*60*24*30, # Expires in 30 days (in seconds)
httponly=True, # Prevent JavaScript access (good for security)
samesite='Lax' # Mitigate CSRF risk
# secure=True # Uncomment if site uses HTTPS only
)
# Set another cookie to remember login time
response.set_cookie(
'last_login',
str(datetime.datetime.now()),
max_age=60*10 # Expires in 10 minutes
)
return response
else:
# Form is invalid, re-render login page with errors
return render(request, 'login.html', {'form': form})
else:
# GET request, show the login form
form = LoginForm()
return render(request, 'login.html', {'form': form})
# A simple dashboard view (target of redirect)
def dashboard_view(request):
return HttpResponse("Welcome to your dashboard!")

Key set_cookie parameters:

  • key: The name of the cookie (string).
  • value: The value to store (string). Non-string values are automatically converted.
  • max_age: The cookie’s lifespan in seconds. If None or omitted, it’s a session cookie (deleted when the browser closes).
  • expires: Alternative to max_age. Takes a datetime object or formatted string. If both are set, max_age takes precedence.
  • path: The URL path for which the cookie is valid (defaults to ’/’).
  • domain: The domain for which the cookie is valid.
  • secure: If True, the cookie is only sent over HTTPS.
  • httponly: If True, the cookie cannot be accessed by client-side JavaScript (helps prevent XSS attacks).
  • samesite: Controls cross-site request behavior (‘Strict’, ‘Lax’, ‘None’). Helps prevent CSRF attacks. Requires secure=True if set to ‘None’.

Cookies sent by the browser are available in the request.COOKIES dictionary-like object.

Let’s create a view that reads the user_theme cookie set earlier.

from django.shortcuts import render
def display_preferences_view(request):
# Use .get() for safe access - returns None if cookie doesn't exist
user_theme = request.COOKIES.get('user_theme', 'light') # Default to 'light'
last_login_str = request.COOKIES.get('last_login')
context = {
'current_theme': user_theme,
'last_login_time': last_login_str
}
return render(request, 'preferences.html', context)

Accessing request.COOKIES['cookie_name'] directly will raise a KeyError if the cookie doesn’t exist. Using request.COOKIES.get('cookie_name', default_value) is safer.

To delete a cookie, use the response.delete_cookie() method. It works by setting the cookie’s expiry date to the past and max_age to 0.

from django.shortcuts import redirect
from django.http import HttpResponse
def logout_view(request):
# Perform logout actions (e.g., clear session data)
# ...
response = redirect('home') # Redirect to home page
# Delete the cookies we set earlier
response.delete_cookie('user_theme')
response.delete_cookie('last_login')
return response
def home_view(request):
return HttpResponse("Welcome home!")

You must pass the same path and domain parameters to delete_cookie as you used when setting the cookie if they were non-default values.

Let’s combine setting and reading to implement a simple timeout based on the last_login cookie (though Django sessions are usually better for real authentication).

import datetime
from django.shortcuts import render, redirect
from django.http import HttpResponse
TIMEOUT_SECONDS = 10 # Short timeout for demonstration
def protected_page_view(request):
last_login_str = request.COOKIES.get('last_login')
if last_login_str:
try:
# Attempt to parse the stored datetime string
# Note: Storing timezone-aware datetimes is more robust
last_login_time = datetime.datetime.strptime(last_login_str.split('.')[0], "%Y-%m-%d %H:%M:%S")
time_difference = datetime.datetime.now() - last_login_time
if time_difference.total_seconds() < TIMEOUT_SECONDS:
# Still within the allowed time
return render(request, 'protected_page.html', {'message': 'Welcome back!'})
else:
# Timeout expired
response = redirect('login') # Redirect to login
response.delete_cookie('last_login') # Clear the expired cookie
return response
except (ValueError, TypeError):
# Handle cases where the cookie value is invalid
response = redirect('login')
response.delete_cookie('last_login')
return response
else:
# No login cookie found
return redirect('login')
def protected_page_html(request):
message = request.GET.get('message', 'This is a protected page.')
return HttpResponse(f"<html><body><h1>Protected Content</h1><p>{message}</p></body></html>")

Remember to add URL patterns for login, dashboard, logout, home, protected_page and the template protected_page.html for this example to work.

While useful, directly manipulating cookies requires careful handling of security and state. For managing user login state, Django’s built-in session framework is generally the preferred and more secure approach.

Further Reading: