Сессии в Django
Сессии позволяют хранить данные между запросами пользователя. Это мощный инструмент для создания персонализированного опыта и управления состоянием пользователя.
Настройка сессий в settings.py
1# settings.py
2SESSION_ENGINE = 'django.contrib.sessions.backends.db' # По умолчанию
3SESSION_COOKIE_AGE = 1209600 # 2 недели в секундах
4SESSION_COOKIE_SECURE = True # HTTPS только
5SESSION_COOKIE_HTTPONLY = True # Защита от XSS
6SESSION_COOKIE_SAMESITE = 'Lax' # CSRF защита
7SESSION_SAVE_EVERY_REQUEST = False # Оптимизация
8SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Сессия после закрытия браузера
Альтернативные движки сессий
1# База данных (по умолчанию)
2SESSION_ENGINE = 'django.contrib.sessions.backends.db'
3
4# Кэш (Redis/Memcached)
5SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
6SESSION_CACHE_ALIAS = 'default'
7
8# Файловая система
9SESSION_ENGINE = 'django.contrib.sessions.backends.file'
10SESSION_FILE_PATH = '/tmp/django_sessions'
11
12# Подписанные куки
13SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
Работа с сессиями в views
Основные операции с сессиями:
1. Сохранение данных в сессию
1def my_view(request):
2 # Простое сохранение
3 request.session['user_preference'] = 'dark_theme'
4
5 # Сохранение сложных данных
6 request.session['user_data'] = {
7 'theme': 'dark',
8 'language': 'ru',
9 'notifications': True
10 }
11
12 # Сохранение списков
13 request.session['recent_items'] = ['item1', 'item2', 'item3']
14
15 # Сохранение с проверкой
16 if 'counter' not in request.session:
17 request.session['counter'] = 0
18 request.session['counter'] += 1
2. Чтение данных из сессии
1def read_session_data(request):
2 # Простое чтение
3 theme = request.session.get('user_preference', 'light_theme')
4
5 # Чтение с проверкой существования
6 if 'user_data' in request.session:
7 user_data = request.session['user_data']
8 language = user_data.get('language', 'en')
9
10 # Безопасное чтение вложенных данных
11 notifications = request.session.get('user_data', {}).get('notifications', False)
12
13 # Получение всех ключей сессии
14 session_keys = list(request.session.keys())
15
16 # Проверка существования ключа
17 has_theme = 'user_preference' in request.session
3. Удаление и очистка сессии
1def manage_session(request):
2 # Удаление конкретного ключа
3 if 'user_preference' in request.session:
4 del request.session['user_preference']
5
6 # Удаление с проверкой
7 request.session.pop('counter', None)
8
9 # Очистка всей сессии
10 request.session.flush()
11
12 # Установка значения в None (удаляет ключ)
13 request.session['temp_data'] = None
14
15 # Очистка устаревших данных
16 if 'old_data' in request.session:
17 del request.session['old_data']
Практические примеры использования
1. Корзина покупок
1def add_to_cart(request, product_id):
2 if 'cart' not in request.session:
3 request.session['cart'] = []
4
5 cart = request.session['cart']
6 if product_id not in cart:
7 cart.append(product_id)
8 request.session['cart'] = cart
9 request.session.modified = True
10
11 return JsonResponse({'cart_count': len(cart)})
12
13def view_cart(request):
14 cart_items = request.session.get('cart', [])
15 products = Product.objects.filter(id__in=cart_items)
16 return render(request, 'cart.html', {'products': products})
17
18def remove_from_cart(request, product_id):
19 cart = request.session.get('cart', [])
20 if product_id in cart:
21 cart.remove(product_id)
22 request.session['cart'] = cart
23 request.session.modified = True
24 return redirect('view_cart')
2. Система уведомлений
1def add_notification(request, message, level='info'):
2 if 'notifications' not in request.session:
3 request.session['notifications'] = []
4
5 notifications = request.session['notifications']
6 notifications.append({
7 'message': message,
8 'level': level,
9 'timestamp': timezone.now().isoformat()
10 })
11
12 # Ограничиваем количество уведомлений
13 if len(notifications) > 10:
14 notifications.pop(0)
15
16 request.session['notifications'] = notifications
17 request.session.modified = True
18
19def get_notifications(request):
20 notifications = request.session.get('notifications', [])
21 # Очищаем после чтения
22 if notifications:
23 request.session['notifications'] = []
24 request.session.modified = True
25 return notifications
3. Система предпочтений пользователя
1def save_user_preferences(request):
2 if request.method == 'POST':
3 preferences = {
4 'theme': request.POST.get('theme', 'light'),
5 'language': request.POST.get('language', 'ru'),
6 'timezone': request.POST.get('timezone', 'Europe/Moscow'),
7 'notifications_enabled': request.POST.get('notifications') == 'on'
8 }
9
10 request.session['user_preferences'] = preferences
11 request.session.modified = True
12
13 return JsonResponse({'status': 'success'})
14
15 return render(request, 'preferences_form.html')
16
17def get_user_preferences(request):
18 return request.session.get('user_preferences', {
19 'theme': 'light',
20 'language': 'ru',
21 'timezone': 'Europe/Moscow',
22 'notifications_enabled': True
23 })
4. Система последних просмотренных страниц
1class RecentPagesMiddleware:
2 def __init__(self, get_response):
3 self.get_response = get_response
4
5 def __call__(self, request):
6 response = self.get_response(request)
7
8 if request.user.is_authenticated:
9 current_url = request.path
10 recent_pages = request.session.get('recent_pages', [])
11
12 if current_url not in recent_pages:
13 recent_pages.insert(0, current_url)
14 # Ограничиваем 10 последними страницами
15 recent_pages = recent_pages[:10]
16 request.session['recent_pages'] = recent_pages
17 request.session.modified = True
18
19 return response
Безопасность сессий
1. Защита от CSRF атак
1# settings.py
2SESSION_COOKIE_SAMESITE = 'Strict' # Для критичных операций
3SESSION_COOKIE_SECURE = True # Только HTTPS
4SESSION_COOKIE_HTTPONLY = True # Защита от JavaScript
5
6# middleware.py
7MIDDLEWARE = [
8 'django.middleware.security.SecurityMiddleware',
9 'django.contrib.sessions.middleware.SessionMiddleware',
10 'django.middleware.csrf.CsrfViewMiddleware',
11 # ... другие middleware
12]
2. Валидация данных сессии
1def validate_session_data(request):
2 # Проверяем целостность данных
3 user_data = request.session.get('user_data', {})
4
5 if not isinstance(user_data, dict):
6 # Сброс поврежденных данных
7 request.session['user_data'] = {}
8 return False
9
10 # Проверяем обязательные поля
11 required_fields = ['theme', 'language']
12 for field in required_fields:
13 if field not in user_data:
14 return False
15
16 return True
17
18def secure_session_view(request):
19 if not validate_session_data(request):
20 # Перенаправляем на страницу восстановления
21 return redirect('restore_session')
22
23 # Продолжаем обработку
24 return render(request, 'secure_page.html')
3. Ограничение размера сессии
1def check_session_size(request):
2 session_data = dict(request.session)
3 session_size = len(str(session_data))
4
5 # Максимальный размер сессии (например, 4KB)
6 max_size = 4096
7
8 if session_size > max_size:
9 # Очищаем старые данные
10 old_keys = ['recent_pages', 'temp_data', 'old_notifications']
11 for key in old_keys:
12 if key in request.session:
13 del request.session[key]
14
15 request.session.modified = True
16 return False
17
18 return True
Управление жизненным циклом сессий
1. Настройка времени жизни
1# settings.py
2SESSION_COOKIE_AGE = 1209600 # 2 недели
3SESSION_EXPIRE_AT_BROWSER_CLOSE = False
4
5# views.py
6def extend_session(request):
7 # Продлеваем сессию на 30 дней
8 request.session.set_expiry(30 * 24 * 60 * 60)
9 request.session.modified = True
10 return JsonResponse({'status': 'session_extended'})
11
12def set_session_expiry(request):
13 if request.POST.get('remember_me'):
14 # Запоминаем на 30 дней
15 request.session.set_expiry(30 * 24 * 60 * 60)
16 else:
17 # Сессия истекает при закрытии браузера
18 request.session.set_expiry(0)
19
20 request.session.modified = True
2. Очистка устаревших сессий
1# management/commands/cleanup_sessions.py
2from django.core.management.base import BaseCommand
3from django.contrib.sessions.models import Session
4from django.utils import timezone
5from datetime import timedelta
6
7class Command(BaseCommand):
8 help = 'Cleanup expired sessions'
9
10 def add_arguments(self, parser):
11 parser.add_argument(
12 '--days',
13 type=int,
14 default=30,
15 help='Remove sessions older than N days'
16 )
17
18 def handle(self, *args, **options):
19 cutoff_date = timezone.now() - timedelta(days=options['days'])
20 deleted_count, _ = Session.objects.filter(
21 expire_date__lt=cutoff_date
22 ).delete()
23
24 self.stdout.write(
25 self.style.SUCCESS(f'Deleted {deleted_count} expired sessions')
26 )
Тестирование сессий
1# tests.py
2from django.test import TestCase, Client
3from django.contrib.auth.models import User
4
5class SessionTestCase(TestCase):
6 def setUp(self):
7 self.client = Client()
8 self.user = User.objects.create_user(
9 username='testuser',
10 password='testpass123'
11 )
12
13 def test_session_storage(self):
14 # Тестируем сохранение в сессию
15 response = self.client.post('/save_preferences/', {
16 'theme': 'dark',
17 'language': 'en'
18 })
19
20 # Проверяем, что данные сохранились
21 session = self.client.session
22 self.assertEqual(session['user_preferences']['theme'], 'dark')
23 self.assertEqual(session['user_preferences']['language'], 'en')
24
25 def test_session_expiry(self):
26 # Тестируем истечение сессии
27 session = self.client.session
28 session['test_data'] = 'value'
29 session.set_expiry(1) # 1 секунда
30 session.save()
31
32 # Ждем истечения
33 import time
34 time.sleep(2)
35
36 # Проверяем, что сессия истекла
37 self.assertNotIn('test_data', self.client.session)
Мониторинг и отладка сессий
1. Логирование операций с сессиями
1import logging
2logger = logging.getLogger(__name__)
3
4def log_session_operation(request, operation, key, value=None):
5 logger.info(
6 f"Session operation: {operation}, "
7 f"User: {request.user.username if request.user.is_authenticated else 'Anonymous'}, "
8 f"Key: {key}, "
9 f"Value: {value}, "
10 f"Session ID: {request.session.session_key}"
11 )
12
13def safe_session_set(request, key, value):
14 try:
15 request.session[key] = value
16 request.session.modified = True
17 log_session_operation(request, 'SET', key, value)
18 return True
19 except Exception as e:
20 logger.error(f"Failed to set session key {key}: {e}")
21 return False
2. Отладочная информация
1def debug_session(request):
2 session_info = {
3 'session_key': request.session.session_key,
4 'session_age': request.session.get('_session_expiry'),
5 'keys': list(request.session.keys()),
6 'modified': request.session.modified,
7 'expiry_date': request.session.get_expiry_date(),
8 'expiry_age': request.session.get_expiry_age(),
9 }
10
11 return JsonResponse(session_info)
12
13# В шаблоне для отладки
14{% if debug %}
15<div class="session-debug">
16 <h4>Session Debug Info:</h4>
17 <p>Session Key: {{ request.session.session_key }}</p>
18 <p>Modified: {{ request.session.modified }}</p>
19 <p>Keys: {{ request.session.keys|join:", " }}</p>
20</div>
21{% endif %}
FAQ
Q: Как настроить время жизни сессии?
A: Используй SESSION_COOKIE_AGE в settings.py для установки времени в секундах. Также можно использовать set_expiry() в коде для динамического управления.
Q: Как очистить все сессии пользователя?
A: Используй request.session.flush() для очистки текущей сессии или удаляй записи из таблицы Session в базе данных.
Q: Можно ли хранить объекты Django в сессии?
A: Сессии сериализуются в JSON, поэтому можно хранить только простые типы данных. Для сложных объектов используй pickle или сохраняй ID.
Q: Как защитить сессии от кражи?
A: Используй HTTPS, установи SESSION_COOKIE_SECURE=True, SESSION_COOKIE_HTTPONLY=True и регулярно обновляй сессии.
Q: Как отследить активность пользователей по сессиям?
A: Логируй операции с сессиями, используй middleware для отслеживания активности и анализируй таблицу Session в базе данных.
Q: Можно ли использовать сессии для кэширования данных?
A: Да, но с осторожностью. Сессии подходят для персональных данных, но для общего кэширования лучше использовать Redis или Memcached.
Q: Как обработать ошибки сериализации сессии?
A: Обрабатывай исключения при работе с сессиями, валидируй данные перед сохранением и используй try-except блоки для критичных операций.
Q: Как синхронизировать сессии между несколькими серверами?
A: Используй Redis или Memcached как движок сессий, или настрой репликацию базы данных между серверами.