← Назад к вопросам

Что такое кеширование шаблонов в Django?

2.0 Middle🔥 151 комментариев
#Python Core#Soft Skills

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Кеширование шаблонов в Django

Кеширование шаблонов в Django — это механизм оптимизации производительности, который заключается в кешировании (сохранении в памяти) результатов рендеринга HTML-шаблонов, чтобы избежать повторной обработки одних и тех же данных. Django предоставляет несколько подходов к кешированию на разных уровнях.

Типы кеширования в Django

1. Кеширование на уровне вью (View-level caching)

Кеширует весь результат представления:

from django.views.decorators.cache import cache_page
from django.shortcuts import render
from .models import Article

# Кеширует результат на 60 секунд
@cache_page(60)
def article_list(request):
    articles = Article.objects.all()
    return render(request, 'articles/list.html', {'articles': articles})

# Используется в urls.py
from django.urls import path

urlpatterns = [
    path('articles/', cache_page(60)(article_list)),
]

2. Кеширование на уровне шаблона (Template-level caching)

Кеширует отдельные блоки шаблона:

{% load cache %}

<!-- Кешируем блок на 300 секунд с ключом 'sidebar' -->
{% cache 300 sidebar user.id %}
    <div class="sidebar">
        <h3>{{ user.name }} Профиль</h3>
        <p>{{ user.bio }}</p>
    </div>
{% endcache %}

<!-- Кешируем список статей -->
{% cache 600 article_list %}
    <div class="articles">
        {% for article in articles %}
            <div class="article">
                <h2>{{ article.title }}</h2>
                <p>{{ article.content|truncatewords:50 }}</p>
            </div>
        {% endfor %}
    </div>
{% endcache %}

3. Кеширование на уровне фрагмента (Fragment caching)

from django.core.cache import cache
from .models import Category

def product_list(request):
    # Пытаемся получить из кеша
    categories = cache.get('all_categories')
    
    # Если не в кеше — получаем из БД и сохраняем
    if categories is None:
        categories = Category.objects.all()
        cache.set('all_categories', categories, 3600)  # На 1 час
    
    return render(request, 'products/list.html', {'categories': categories})

Настройка кеша в Django

settings.py:

# Использование Redis (рекомендуется для production)
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
            'CONNECTION_POOL_KWARGS': {'max_connections': 50}
        }
    }
}

# Использование локального памяти (для разработки)
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
    }
}

# Использование базы данных
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }
}

# Использование файловой системы
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
    }
}

Примеры работы с кешем

Базовые операции с cache API:

from django.core.cache import cache

# Установка значения в кеш
cache.set('user_profile:123', user_data, 3600)  # Живёт 1 час

# Получение значения из кеша
user_data = cache.get('user_profile:123')

# Получение с значением по умолчанию
user_data = cache.get('user_profile:123', default={})

# Проверка наличия ключа
if cache.has_key('user_profile:123'):
    print("Есть в кеше")

# Удаление из кеша
cache.delete('user_profile:123')

# Очистка всего кеша
cache.clear()

# Увеличение значения (если число)
cache.incr('page_views', 1)

# Установка если не существует
cache.add('lock_key', 'locked', 60)  # Вернёт False если уже есть

Кеширование функций

from django.views.decorators.cache import cache_page
from django.core.cache import cache
from functools import wraps

# Встроенный декоратор для функций
def cache_result(timeout=3600):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Генерируем ключ кеша на основе имени функции и параметров
            cache_key = f"{func.__name__}:{args}:{kwargs}"
            
            result = cache.get(cache_key)
            if result is None:
                result = func(*args, **kwargs)
                cache.set(cache_key, result, timeout)
            
            return result
        return wrapper
    return decorator

# Использование
@cache_result(timeout=1800)
def get_expensive_data(user_id):
    # Дорогостоящая операция
    return expensive_calculation(user_id)

Инвалидация кеша

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.cache import cache
from .models import Article

# Очищаем кеш при обновлении статьи
@receiver(post_save, sender=Article)
def invalidate_article_cache(sender, instance, **kwargs):
    # Удаляем кеш списка статей
    cache.delete('all_articles')
    cache.delete('featured_articles')
    
    # Удаляем кеш конкретной статьи
    cache.delete(f'article:{instance.id}')

Кеширование с Vary HTTP headers

from django.views.decorators.cache import cache_page, vary_on_headers
from django.shortcuts import render

# Кешируем отдельно для каждого пользователя
@cache_page(60)
@vary_on_headers('Cookie')
def user_dashboard(request):
    return render(request, 'dashboard.html', {'user': request.user})

# Кешируем отдельно для каждого User-Agent
@cache_page(60)
@vary_on_headers('User-Agent')
def home(request):
    return render(request, 'home.html')

Низкоуровневое кеширование в шаблоне

{% load cache %}

<!-- Ключ кеша зависит от пользователя -->
{% cache 600 user_sidebar user.id %}
    <aside class="sidebar">
        <h3>Мой профиль</h3>
        <p>{{ user.email }}</p>
        <ul>
            {% for notification in user.notifications %}
                <li>{{ notification.message }}</li>
            {% endfor %}
        </ul>
    </aside>
{% endcache %}

Best practices

1. Используй осмысленные ключи кеша:

# ПЛОХО
cache.set('key', data, 3600)

# ХОРОШО
cache.set(f'user_profile:{user_id}', user_data, 3600)
cache.set(f'category_products:{category_id}', products, 1800)

2. Выбирай правильный timeout:

# Для пользовательских данных — короче
cache.set('user_data', data, 300)  # 5 минут

# Для статических данных — дольше
cache.set('categories', categories, 86400)  # 1 день

# Для очень динамичных данных — вообще не кешируй

3. Инвалидируй кеш правильно:

from django.db.models.signals import post_delete

@receiver(post_delete, sender=Article)
def invalidate_on_delete(sender, instance, **kwargs):
    cache.delete(f'article:{instance.id}')
    cache.delete('all_articles')

4. Мониторь эффективность кеша:

from django.views.decorators.cache import cache_page

# Используй Django Debug Toolbar для анализа
# или добавь логирование попаданий/промахов

def log_cache_stats():
    # Некоторые бэкенды поддерживают статистику
    stats = cache._cache.get_stats()  # Redis пример
    print(f"Cache hits: {stats['hits']}, misses: {stats['misses']}")

Когда использовать кеширование

  • Часто запрашиваемые данные — списки категорий, популярные посты
  • Дорогостоящие операции — сложные аналитики, расчёты
  • Медленные запросы к БД — запросы с multiple joins
  • Внешние API запросы — данные от сторонних сервисов

Когда НЕ использовать:

  • Критичные данные — актуальность важнее, чем скорость
  • Личные данные — безопасность важнее
  • Часто меняющиеся данные — инвалидация будет частой

Вывод: Кеширование — мощный инструмент для оптимизации Django приложений. Правильное использование может значительно улучшить производительность, но требует осмысленного подхода к инвалидации и выбору данных для кеша.

Что такое кеширование шаблонов в Django? | PrepBro