Ось готовий урок, створений за твоїм майстер-промптом.
🎓 CS50-style Lesson: Кешування в Django
Привіт, друзі! 👋 Радий бачити вас. Сьогодні ми поговоримо про те, що відрізняє "просто сайт" від сайту, який літає як ракета. Ми поговоримо про швидкість.
1. 🔥 Вступ: Чому ваш сайт "тупить"?
Уявіть, що ви прийшли до бібліотеки. Ви підходите до бібліотекаря і питаєте: "Де лежить книга 'Гаррі Поттер'?".
Бібліотекар встає, йде в архів, шукає по полицях 5 хвилин, повертається, витирає піт з чола і каже: "Третій ряд, полиця 4". Ви дякуєте і йдете.
Через хвилину підходить інший студент і питає: "Де лежить книга 'Гаррі Поттер'?". І що робить бібліотекар? Він знову йде в архів, знову шукає 5 хвилин!
Звучить абсурдно, правда? Чому б йому просто не запам'ятати це? Або не записати на стікері перед собою?
Ось так працює ваш Django-проєкт за замовчуванням. Кожного разу, коли користувач відкриває сторінку: 1. Django з’єднується з базою даних (йде в архів). 2. Виконує важкі SQL-запити (шукає книгу). 3. Рендерить HTML-шаблон (формулює відповідь). 4. Віддає сторінку.
А якщо на сайт зайде 1000 людей одночасно? Ваш "бібліотекар" (сервер) впаде від виснаження.
Сьогодні ми навчимо його користуватися "стікерами". Ми навчимо його Кешуванню.
2. 🧠 Теоретична база: Як це працює "під капотом"
Отже, кешування — це збереження результату складної операції, щоб наступного разу не робити її знову, а просто віддати готовий результат.
У комп'ютерних науках це працює як величезний словник (Dictionary), або Hash Map, якщо хочете звучати професійно.
У ньому є лише дві головні речі:
* Ключ (Key): Унікальне ім'я (наприклад, homepage_data).
* Значення (Value): Готовий шматок даних (наприклад, готовий HTML-код або список товарів).
Як виглядає життєвий цикл запиту з кешем?
- Запит: Користувач стукає: "Дай мені головну сторінку!".
- Перевірка (Cache Hit?): Django дивиться в кеш: "Ми вже робили це?".
- ✅ ТАК (Hit): Супер! Беремо готове, віддаємо миттєво. База даних навіть не прокидається.
- ❌ НІ (Miss): Окей, доведеться працювати. Робимо запит в БД, рендеримо шаблон.
- Збереження (Set): Перед тим як віддати результат користувачу, ми кладемо його в кеш: "Запам'ятай це на 15 хвилин".
⚠️ Що треба знати залізно:
- TTL (Time To Live): Час життя кешу. Дані не можуть жити вічно, інакше користувачі бачитимуть старі новини.
- Backend: Де ми це зберігаємо?
- Пам’ять (RAM): Дуже швидко (Redis, Memcached).
- Файл/База даних: Повільніше, але надійно.
- Local Memory: (за замовчуванням в Django) — зберігає просто в пам’яті процесу Python. Окей для розробки, погано для продакшену.
3. 🧪 Приклади: Від простого до магії
Django робить кешування неймовірно простим. Давайте подивимось.
Рівень 1: Low-level API (Ручне керування)
Уявіть, що у нас є "важка" функція, яка рахує кількість активних користувачів (це навантажує БД).
from django.core.cache import cache
from myapp.models import User
import time
def get_active_users_count():
# 1. Спробуємо дістати з кешу по ключу 'active_users'
count = cache.get('active_users')
# Що ви очікуєте побачити в змінній count при першому запуску?
# Правильно, None. Бо там ще нічого немає.
if count is None:
print("💡 Рахуємо чесно (довго)...")
# Імітація важкої роботи
time.sleep(2)
count = User.objects.filter(is_active=True).count()
# 2. Зберігаємо в кеш на 60 секунд
cache.set('active_users', count, timeout=60)
else:
print("🚀 Взяли з кешу (миттєво)!")
return count
Результат: * Перший виклик: затримка 2 сек, повідомлення "Рахуємо чесно...". * Другий виклик (через 5 сек): миттєво, "Взяли з кешу!". * Третій виклик (через 61 сек): знову затримка 2 сек (бо TTL вийшов).
Рівень 2: Per-View Caching (Найпопулярніший)
Ми хочемо закешувати цілу сторінку. Навіщо писати логіку перевірки вручну, якщо можна використати декоратор?
from django.views.decorators.cache import cache_page
# Кешуємо цю сторінку на 15 хвилин (900 секунд)
@cache_page(60 * 15)
def heavy_report_view(request):
# Тут виконуються страшні запити до БД
data = ...
return render(request, 'report.html', {'data': data})
Що відбувається?
Django бере URL сторінки як ключ. Якщо хтось заходить на цю ж адресу — функція heavy_report_view навіть не запускається. Django віддає збережений HTML одразу.
Рівень 3: Template Fragment Caching (Хірургічна точність)
Уявіть сайт новин. * Стрічка новин змінюється раз на годину. * Але блок "Привіт, [Ім'я Користувача]" у хедері — унікальний для кожного!
Якщо ми закешуємо всю сторінку, Василь побачить "Привіт, Петро", бо Петро зайшов першим. Це катастрофа. 😱
Тут ми кешуємо тільки шматочок шаблону:
{% load cache %}
<!-- Хедер динамічний, не кешуємо -->
<h1>Привіт, {{ user.username }}!</h1>
<!-- А ось сайдбар з погодою кешуємо на 500 секунд -->
{% cache 500 sidebar %}
<div class="weather-widget">
<!-- Тут якась важка логіка виводу погоди -->
...
</div>
{% endcache %}
4. 🛠 Практична частина
Час забруднити руки кодом! Відкрийте ваш Django-проект (або створіть тестовий).
Завдання 1: Налаштування
Додайте в settings.py просте локальне кешування (це default, але пропишіть явно, щоб бачити):
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
}
}
Завдання 2: "Таймер"
Створіть в’юху (view), яка виводить поточний час (datetime.now()).
* Відкрийте сторінку -> час оновлюється при кожному F5.
* Додайте декоратор @cache_page(30).
* Оновіть сторінку (F5). Час завмер? Чому? Зачекайте 30 секунд. Що сталося?
Завдання 3: "Проблема свіжості"
* Зробіть в’юху, яка виводить список усіх статтей з БД. Закешуйте її на 1 годину.
* Зайдіть в адмінку і додайте нову статтю.
* Поверніться на сторінку списку. Статті немає. Чому?
* Чекпоінт: Як змусити користувачів побачити статтю, не чекаючи годину? (Підказка: гугліть cache invalidation або змініть ключ).
Завдання 4: Міні-кейс
У вас є інтернет-магазин.
* Ціна товару змінюється рідко.
* Кількість на складі змінюється кожну хвилину.
* Завдання: Використайте {% cache %} у шаблоні так, щоб опис і фото товару бралися з кешу, а ціна і наявність — завжди були актуальні.
5. 💡 Мислення як у розробника
Ви тепер знаєте, як увімкнути кеш. Але досвідчений сеньйор відрізняється від джуна не знанням команди cache.set, а розумінням того, КОЛИ її не можна використовувати.
Типові пастки (Junior Mistakes):
- Кешування персональних даних. Ніколи не кешуйте всю сторінку, якщо там є приватна інформація користувача. Інакше один юзер побачить корзину товарів іншого.
- Передчасна оптимізація. Не кешуйте все підряд. Спочатку профілюйте (заміряйте), що саме гальмує. Можливо, вам просто треба додати індекс в БД?
- Забута інвалідація. Найгірше для бізнесу — коли ви змінили ціну на сайті, а клієнти бачать стару ще добу.
Як думає профі:
"Є така приказка в Computer Science: 'Існує лише дві складні речі: інвалідація кешу та вигадування назв для змінних'."
Коли я додаю кеш, я завжди питаю себе: 1. Наскільки часто ці дані змінюються? (Раз на рік? Раз на секунду?) 2. Що станеться, якщо юзер побачить старі дані? (Катастрофа чи "і так зійде"?) 3. Як я буду очищати цей кеш, якщо дані зміняться? (Сигнали Django? Ручне видалення?)
6. 🧩 Підсумок
Отже, що ми сьогодні зробили?
1. Ми зрозуміли, що ходити в базу даних постійно — дорого.
2. Ми навчилися використовувати "пам'ять" (кеш), щоб зберігати готові відповіді.
3. Ми розібрали три стратегії: Low-level API, Per-View та Template Fragment.
Що ви тепер вмієте? Ви можете взяти повільну сторінку, яка вантажиться 2 секунди, і змусити її відкриватися за 20 мілісекунд. Ви фактично купуєте час за пам'ять.
🚀 Тизер наступного уроку
Але що робити, якщо операція настільки важка (наприклад, обробка відео або відправка 1000 email-ів), що користувач не може чекати навіть один раз, поки ми покладемо це в кеш? Тут нам знадобиться "магія" фонових задач. Наступного разу ми поговоримо про Celery та асинхронність.
А поки що — спробуйте закешувати щось у своєму пет-проєкті. Це магія CS50! 🏛️