Введение
Как известно, в настоящее время производительность является одним из наиболее важных аспектов при разработке веб-приложений. И так как ответы сервера на различные запросы пользователей быват схожи или даже идентичны, приложения используют механизмы кэширования. Одним из уровней кэша является серверный кэш, о котором далее пойдет речь. В статье будет рассмотрен механизм серверного кэша, поставляемый "из коробки" с фреймворком Django.
Django Cache поддерживает различные типы кэш-провайдеров, такие как Memcached или Redis. Кэширование может быть применено к представлениям (views), фрагментам шаблонов (template fragments) и результатам запросов к базе данных и их обработки.
Установка и настройка
Настроить кэш в Django несложно. Для этого нужно просто добавить в файл с настроками settings.py
параметры провайдера. Пример для Memcached:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
Использование для кэширования представлений
Данный вид кэширования может быть полезен, если ваши представления (views) не зависят от контекста исполнения. Например, представление, которое отдает некоторую выборку из базы данных. Пример:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # Кэшируем представление на 15 минут
def my_view(request):
# Реализация представления
# ...
return HttpResponse(result)
Использование для кэширования фрагментов шаблонов
Данный вид кэширования может быть использован при написании приложения на Django-шаблонах. Например, когда при исполнении запроса ответ зависит от контекста, но только частично: имеются части, содержимое которых остается неизменным. В таком случае можно оптимизировать формирование ответов, закешировав предварительно сформированные фрагменты шаблонов:
from django.views.decorators.cache import cache_page
from django.template.loader import render_to_string
def expensive_fragment():
# Реализация дорогостоящего фрагмента
# ...
# Возвращаем результат фрагмента
return result
def my_view(request):
fragment = cache.get('my_fragment_cache_key')
if fragment is None:
# Фрагмент не найден в кэше, выполняем дорогостоящую операцию
fragment = expensive_fragment()
# Сохраняем фрагмент в кэше на 5 минут
cache.set('my_fragment_cache_key', fragment, 300)
context = {
'fragment': fragment,
}
return HttpResponse(render_to_string('my_template.html', context))
Использование для кэширования данных из базы данных
Наконец, вероятно наиболее популярный случай использования серверного кэша: сохранение некоторого набора данных, полученных из БД. Популярность обусловлена тем, что в среднем получение данных из кэша намного быстрее выборки из базы. К тому же, данные можно закэшировать уже после их обработки кодом. Это также положительно скажется на производительности, т.к. практика показывает, что обработка большого объема данных в Python бывает очень медленной.
Пример такого подхода:
from django.core.cache import cache
from .models import Product
def get_products():
products = cache.get('products_list')
if products is None:
# Результат не найден в кэше, выполняем запрос к базе данных
products = Product.objects.all()
# Выполняем обработку
products = ...
# Сохраняем результат в кэше на 1 час
cache.set('products_list', products, 3600)
return products
Стоит также отметить то, что можно также настроить раздельное кэширование для запросов пользователей. Для этого достаточно в формирование ключа включить идентификатор пользователя:
cache.set(f'products_list_{user.username}', products, 3600)
cache.get(f'products_list_{user.username}')
Аналогично можно разделять кэш не только для различных пользователей, но и по любым другим параметрам.
Инвалидация кэша
Конечно же, Django cache предоставляет также и механизм инвалидации кэша. Его стоит использовать для досрочного удаления данных из кэша при, например, изменении состояния закэшированных данных в базе данных. Например:
from django.core.cache import cache
from .models import Product
def update_product(product_id):
# Обновление данных о продукте в базе данных
# ...
# Инвалидация соответствующего элемента кэша
cache.delete('product_{}'.format(product_id))
Выводы
При правильном использовании встроенные в Django механизмы кэширования позволяют полноценно реализовать серверный кэш для вашего приложения, повысив его производительность и уменьшив вычислительную нагрузку на сервер и базы данных. Однако не стоит забывать о том, что кэширование ради кэширования - это не совсем правильно, и стоит провести тестирование производительности для определения мест, где его использование действительно необходимо.