Эта статья была первоначально написана Мухаммедом Али в блоге разработчиков Honeybadger.
Вы когда-нибудь задавались вопросом, что такое кэширование и можно ли это сделать в Django? Хотели бы вы демистифицировать всю концепцию кэширования в Django? Если вы задавались этими вопросами, то вам повезло!
В веб-разработке кэширование — это слой, который хранит данные, которые часто извлекаются, чтобы будущие запросы выполнялись быстрее, чем при попытке получить доступ к этим данным из основной базы данных. Используя кэширование, вы обмениваете емкость на скорость. В отличие от основной базы данных, которая содержит все данные, кэшированные данные являются лишь подмножеством данных, хранящихся в базе данных.
В этой статье я рассмотрю сценарии, в которых вы можете захотеть применить кэширование, а также различные инструменты и способы кэширования в приложении Django. Кэширование в Django требует небольшой настройки; вам просто нужно указать Django, где вы хотите хранить данные кэша, а об остальном вы позаботитесь сами. Давайте приступим к этому!
- Предварительные условия
- Причины и места для кэширования
- Настройка системы кэширования
- Memcached
- Кэш базы данных
- Кэширование файловой системы
- Кэш локальной памяти
- Запуск базового проекта
- Уровни кэширования в Django
- Кэширование фрагментов шаблонов
- Per-site Cache
- Кэширование перед просмотром
- API низкоуровневого кэширования
- Кэширование в Django с помощью Redis
- Заключение
Предварительные условия
Чтобы следовать этой статье, необходимо следующее:
- Предварительные рабочие знания Django и Python
- Python v3.x
- Django v3.x
- Redis v5.x
Причины и места для кэширования
Ниже перечислены причины, по которым вам следует рассмотреть возможность кэширования в вашем приложении:
- Если удаленный сервер не работает или падает, пользователи все равно могут получить доступ к кэшированной копии на прокси-сервере, что повышает надежность вашего приложения.
- Кэширование уменьшает задержку доступа в том смысле, что часто используемые данные извлекаются из близлежащего прокси-кэша, а не из самой базы данных; таким образом, задержка передачи данных сводится к минимуму.
- Кэширование снижает нагрузку на серверную инфраструктуру за счет широкого распространения данных среди более быстрых альтернативных мест хранения данных.
При выборе места для кэширования в вашем Django-приложении, вот некоторые моменты, которые вы должны учитывать:
- Какие представления/шаблоны содержат больше всего запросов? Это будут лучшие места для кэширования.
- Какие модели запрашиваются чаще всего?
Настройка системы кэширования
Существуют различные способы настройки кэширования, в зависимости от того, где вы хотите хранить кэш. Способы, которыми вы можете настроить кэширование в вашем Django-приложении, рассматриваются в следующих разделах.
Memcached
Это самая эффективная система кэширования, поддерживаемая в Django. Memcached предоставляет быстрый интерфейс для добавления, извлечения и удаления данных из кэша. Здесь все данные хранятся непосредственно в памяти, а не в базе данных, что делает доступ к данным более быстрым. Memcached работает как демоны, и им выделяется некоторое количество оперативной памяти.
Чтобы настроить его, вам нужно сначала установить Memcached на локальной машине, а затем установить Python Memcached binding, поддерживаемый Django. Две из них поддерживаются Django: pylibmc и pymemcache.
В этом примере я буду использовать pymemcache.
Чтобы использовать Memcached в Django, перейдите в ваш файл [settings.py](http://settings.py)
, установите BACKEND
в значение
В этом примере Memcached запущен на localhost (127.0.0.1
) порт 9000
.
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': '127.0.0.1:9000',
}
}
Кэш базы данных
Если вы хотите сохранить кэшированные данные в базе данных, Django имеет бэкенд для этой цели.
Чтобы сохранить кэшированные данные в базе данных, вам просто нужно создать таблицу в базе данных, перейдя в файл settings.py
, установив BACKEND
в django.core.cache.backends.db.DatabaseCache
, и установив LOCATION
в tablename
, что является именем таблицы, в которой вы хотите хранить кэш.
Убедитесь, что имя, используемое для таблицы, еще не используется в базе данных.
Затем создайте таблицу базы данных для кэшированных данных, выполнив команду
$ python manage.py createcachetable
Кэширование файловой системы
Кэширование файловой системы предполагает сохранение кэшированных данных в отдельном файле. Для этого установите BACKEND
в django.core.cache.backends.filebased.FileBasedCache
и LOCATION
в /path/to/django_cache
.
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/path/to/django_cache',
# for windows users: 'c:/path/to/django_cache'
}
}
Кэш локальной памяти
Кэш локальной памяти — это кэш по умолчанию, если не заданы никакие настройки. Хотя он почти такой же быстрый, как Memcached, он не может масштабироваться дальше одного сервера. Поэтому он не подходит для использования в качестве кэша данных для приложений, использующих более одного веб-сервера.
Кэширование локальной памяти лучше всего подходит для локальной среды разработки и тестирования.
Кэш LOCATION
используется для идентификации отдельных хранилищ памяти. Чтобы использовать его, установите BACKEND
в django.core.cache.backends.locmem.LocMemCache
.
Ниже приведен пример:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
Запуск базового проекта
Сначала клонируйте предварительно созданный проект Django с некоторыми данными, чтобы мы могли протестировать функциональность кэширования.
Когда вы клонируете проект, создайте для него виртуальную среду и выполните команду
$ pip install -r requirements.txt
для установки зависимостей.
Далее запустите $ python manage.py runserver
, чтобы запустить проект, а затем перейдите на http://localhost:8000/recipe в вашем браузере, чтобы отобразить содержимое проекта.
Вы должны увидеть что-то похожее на страницу, показанную выше. Обратите внимание на вкладки Time и SQL; они указывают на то, что ваш кэш работает.
Уровни кэширования в Django
Django предоставляет различные уровни, на которых вы можете кэшировать Django-приложение. Это обеспечивает детализацию при кэшировании вашего приложения. В этом разделе я расскажу об уровнях, которые предоставляет Django, и применю их к проекту Django, который вы только что клонировали. Уровни обсуждаются в следующих разделах.
Кэширование фрагментов шаблонов
Кэширование фрагментов шаблонов дает вам наибольший контроль над тем, что будет кэшироваться на вашем сайте. Кэширование фрагментов шаблона позволяет вам кэшировать определенные части вашего шаблона, где выполняются большие вычисления. Мы можем сделать это с помощью тега шаблона cache, {% cache %}
.
Чтобы ваш шаблон мог обращаться к этому тегу, поместите {% load cache %}
в начало вашего шаблона и закройте его {% endcache %}
. Тег шаблона {% cache %}
кэширует содержимое блока на определенный период. Требуется как минимум два аргумента: таймаут кэширования (в секундах) и имя для указания фрагмента кэша. Если таймаут равен None
, кэширование в шаблоне будет продолжаться неограниченное время.
Пример:
Откройте проект, который вы только что клонировали, с помощью удобного текстового редактора, перейдите в app/templates/app/recipes.html и вставьте приведенный ниже код.
{% load cache %}
<html>
<head>
<title>Recipes</title>
<style>
body {
background-color:yellow;
}
</style>
</head>
<body>
{% cache 500 recipe %}
{% for recipe in recipes %}
<h1>{{ recipe.name }}</h1>
{% autoescape off %}
<p>{{ recipe.desc }}</p>
{% endautoescape %}
<h2>Ingredients</h2>
<ul>
{% for ingredient in recipe.ingredient_set.all %}
<li>{{ ingredient.description }}</li>
{% endfor %}
</ul>
{% endfor %}
{% endcache %}
</body>
</html>
Теперь, если вы снова запустите проект, вы заметите некоторые изменения. Если вы посмотрите внимательно, то увидите, что время процессора и количество SQL-запросов резко сократились. Это говорит о том, что ваш сайт был закеширован, и теперь он работает быстрее.
Вот изображение продукта для кэширования шаблонов:
Per-site Cache
Это самый простой способ кэширования после настройки бэкенда кэширования. Чтобы его реализовать, сначала нужно добавить классы промежуточного ПО для кэширования в файл settings.py:
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware', #new
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware', #new
]
Затем, все еще находясь в файле settings.py, добавьте следующий код:
CACHE_MIDDLEWARE_ALIAS = 'default' # The cache alias to use for storage and 'default' is **local-memory cache**.
CACHE_MIDDLEWARE_SECONDS = '600' # number of seconds before each page is cached
CACHE_MIDDLEWARE_KEY_PREFIX = '' # This is used when cache is shared across multiple sites that use the same Django instance. You use an empty string if you don’t care for it.
Кэширование перед просмотром
Здесь используется декоратор django.views.decorators.cache.cache_page()
. Per-view обеспечивает более детальный способ использования кэшированных данных путем кэширования вывода отдельных представлений. При использовании кэширования per-view ваше представление будет выглядеть следующим образом:
from django.shortcuts import render
from .models import Recipe
from django.views.decorators.cache import cache_page
@cache_page(600)
def recipes_view(request):
recipes = Recipe.objects.all()
return render(request, 'app/recipes.html', {
'recipes': recipes
})
cache_page
принимает единственный аргумент: таймаут кэширования, в секундах, в данном случае 600 секунд.
В отличие от кэширования для каждого сайта, при кэшировании для каждого просмотра вы можете сохранить память для тех частей сайта, которые действительно в ней нуждаются. Если несколько URL указывают на одно и то же представление, каждый URL будет кэшироваться отдельно.
API низкоуровневого кэширования
Низкоуровневое кэширование означает, что у вас есть возможность контролировать то, что будет кэшироваться на сайте. Например, у вас может быть представление на сайте, результаты которого зависят от нескольких дорогих запросов, и эти результаты меняются через разные промежутки времени. В этом случае не идеально использовать полностраничное кэширование, предлагаемое стратегиями кэширования на сайт и на представление, поскольку вы не хотите кэшировать весь вывод (так как некоторые данные часто меняются). Однако вы все же хотите кэшировать результаты, которые редко меняются. Для этого вы можете использовать низкоуровневый API Django для управления отдельными объектами в кэше с помощью ключа кэша.
Для этого примера мы по-прежнему будем использовать проект, который вы только что клонировали.
В файл view.py вставьте следующий код:
from django.shortcuts import render
from .models import Recipe
from django.core.cache import cache
def cache_recipes_view(request):
recipes = cache.get('recipes')
if recipes is None:
recipes = Recipe.objects.all()
cache.set('recipes', recipes)
return render(request, 'app/recipes.html', {
'recipes': recipes
})
Затем обновите URL, чтобы он выглядел следующим образом:
from django.contrib import admin
from django.urls import path, include
import debug_toolbar
# from app.views import recipes_view
from app.views import cache_recipes_view #new
urlpatterns = [
path('admin/', admin.site.urls),
# path('recipe', recipes_view),
path('cache_recipe', cache_recipes_view), #new
path('__debug__/', include(debug_toolbar.urls)),
]
Теперь, если вы откроете http://localhost:8000/cache_recipe в вашем браузере, вы увидите некоторое сокращение процессорного времени и SQL запросов по сравнению с исходными данными.
Кэширование в Django с помощью Redis
Redis — это хранилище структур данных с открытым исходным кодом, которое может использоваться как база данных, кэш, брокер сообщений и т.д. Чтобы начать использовать Redis в своем Django-приложении, вам нужно сначала установить библиотеку django-redis. Библиотека упрощает подключение вашего Django-приложения к Redis.
$ pip install django-redis
Затем добавьте код, показанный ниже, в файл settings.py так же, как вы делали это для Memcached.
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
Обновите файл views.py:
from django.shortcuts import render
from .models import Recipe
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def recipes_view(request):
recipes = Recipe.objects.all
return render(request, 'app/recipes.html', {
'recipes': recipes
})
Далее, запустите ваш Django сервер $ python manage.py runserver
. Затем перейдите в другое окно терминала и запустите сервер Redis. Вы можете запустить сервер Redis с помощью команды $ redis-cli -n 1
.
После этого ваш бэкенд кэширования Django будет подключен к Redis.
Теперь перейдите на сайт http://localhost:8000/recipe в браузере, и вы увидите, что ваш сайт был оптимизирован, как и ожидалось.
Вы можете проверить, обрабатывается ли ваш кэш Redis, перейдя на вкладку, где запущен сервер redis, и запустив 127.0.0.1:6379[1]> keys *
; вы увидите что-то вроде следующего:
1) ":1:views.decorators.cache.cache_header..5cf60c9557a12db6b6423fc6f291090e.en-us.UTC"
2) ":1:views.decorators.cache.cache_page..GET.5cf60c9557a12db6b6423fc6f291090e.d41d8cd98f00b204e9800998ecf8427e.en-us.UTC"
Скопируйте имя ключа cache_page и введите его с помощью команды get
:
127.0.0.1:6379[1]> get ":1:views.decorators.cache.cache_page..GET.5cf60c9557a12db6b6423fc6f291090e.d41d8cd98f00b204e9800998ecf8427e.en-us.UTC"
Когда вы выполните эту команду, вы должны увидеть отрисованную HTML-строку, которая показывает, что ваш сайт кэшируется на Redis.
Заключение
Цель этой статьи заключалась в том, чтобы провести вас от незнания чего-либо о кэшировании в приложениях Django к демонстрации различных способов, которыми вы можете кэшировать данные при создании приложений Django. Надеюсь, мне это удалось.
С помощью этой статьи вы сможете добавить кэширование в любую часть вашего приложения. Не рекомендуется кэшировать весь сайт, если только у вас нет избытка памяти и вы не заботитесь о сокращении расходов. Старайтесь принимать взвешенные решения при выборе частей сайта для кэширования.
Теперь, когда вы узнали все это, надеюсь, вы будете уверенно применять полученные знания в своих будущих проектах Django или когда этого потребует компания, в которой вы работаете.