В первой части мы реализовали базовый функционал корзины покупок, используя стандартные модели Django и реляционную базу данных. Это надежный подход, но у него есть критический недостаток: каждое добавление товара, изменение количества или удаление позиции создает лишнюю нагрузку на БД и генерирует множество мелких транзакций.
Когда ваш магазин вырастет с 100 до 10 000 пользователей, постоянные запись/чтение временных данных корзины станут «узким местом». Для решения этой проблемы идеально подходит Redis — высокопроизводительное хранилище структур данных в памяти.
Почему Redis?
Корзина покупок по своей природе является временным объектом. Пользователю не важно, сохранятся ли его товары в корзине через год, но ему важно, чтобы страница обновлялась мгновенно.
Преимущества Redis перед SQL:
1. Скорость: Данные хранятся в RAM, что обеспечивает доступ за микросекунды.
2. TTL (Time To Live): Можно настроить автоматическое удаление корзины через 24 часа или неделю.
3. Снижение нагрузки: База данных освобождается для действительно важных операций (оформление заказов, управление каталогом).
Настройка окружения
Для начала установим необходимую библиотеку:
pip install django-redis
Добавим конфигурацию в settings.py:
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
Реализация логики корзины
Вместо использования Django Models, мы создадим класс-обертку, который будет взаимодействовать с кешем. Мы будем использовать JSON-сериализацию для хранения данных о товарах.
Создадим файл cart.py:
from django.core.cache import cache
class RedisCart:
def __init__(self, session_id):
self.session_id = f"cart_{session_id}"
self.ttl = 60 * 60 * 24 * 7 # Корзина живет 7 дней
def add(self, product_id, quantity=1):
cart = self.get()
product_id = str(product_id)
if product_id in cart:
cart[product_id] += quantity
else:
cart[product_id] = quantity
self.save(cart)
def remove(self, product_id):
cart = self.get()
cart.pop(str(product_id), None)
self.save(cart)
def get(self):
# Возвращаем словарь или пустой словарь, если корзины нет
return cache.get(self.session_id, {})
def save(self, cart_data):
cache.set(self.session_id, cart_data, timeout=self.ttl)
def clear(self):
cache.delete(self.session_id)
Интеграция в Views
Теперь обновим наше представление (View), чтобы оно использовало RedisCart вместо моделей БД. Для идентификации пользователя мы будем использовать session_key.
from django.shortcuts import redirect
from .cart import RedisCart
def add_to_cart(request, product_id):
# Гарантируем наличие сессии
if not request.session.session_key:
request.session.create()
cart = RedisCart(request.session.session_key)
cart.add(product_id)
return redirect('cart_detail')
Сравнение подходов: SQL vs Redis
| Характеристика | PostgreSQL/MySQL | Redis |
|---|---|---|
| Место хранения | Диск (SSD/HDD) | Оперативная память (RAM) |
| Скорость записи | Средняя (транзакции) | Экстремально высокая |
| Очистка данных | Ручной запуск скриптов очистки | Автоматический TTL |
| Нагрузка на CPU | Высокая при индексации | Минимальная |
Когда стоит вернуться к БД?
Несмотря на все плюсы Redis, есть случаи, когда реляционная база всё еще нужна:
- Синхронизация между устройствами: Если вы хотите, чтобы пользователь видел одну и ту же корзину в мобильном приложении и в браузере (в этом случае Redis всё равно можно использовать, но данные должны быть привязаны к user_id, а не к session_id).
- Аналитика: Если отдел маркетинга хочет анализировать «брошенные корзины» через сложные SQL-запросы.
Заключение
Перенос корзины в Redis — это один из самых простых и эффективных способов оптимизировать Django-приложение. Мы убрали лишние запросы к основной БД и добавили автоматическое управление жизненным циклом временных данных. В следующей части мы разберем, как интегрировать эту систему с платежным шлюзом и конвертировать Redis-корзину в полноценный заказ в базе данных.