Comments 51
При включенном кэшировании всего сайта часто бывает полезно поставить CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
чтобы включить полный кэш для анонимов, а для остальных использовать блочное/per-view кэширование.
А если у меня нет регистрации и пользователе-зависимой информации? Но, к примеру, блоки рандомно меняются. Мне все-таки кажется что кешировать все подряд не стоит - лучше кешировать то, что действительно нужно.
Ну _если_ включено для всего сайта, то тогда это уже обдумано :)
:)
мне просто интересно когда это может быть надо. разве что если на серваке куча сайтов и один из них совсем не меняется...
Как и обещал - статья про кэширование в Django.
Странно у меня получается - делал блог чтоб писать о JavaScript, а пишу, в основном, о Django. Наверное потому, что блог делал на нем и нахожусь под впечатлением. Вот что значит грамотная архитектура!
Еще интересное - это кэширование view-ов и sql запросов, если они не в темплейтах вызываются.
Плюс обновление кэша по сигналам ;)
Про кэширование view-ов я вроде написал вкратце.
Для кэширования sql запросов можно воспользоваться "кэшированием данных":

from blog.models import Article
from django.core.cache import cache
articles=list(Article.objects.all())
cache.set('articles',articles)
articles_cached=cache.get('articles')
print articles_cached

проверил только что - вроде все работает.

На счет обновления кэша по сигналам - действительно я об этом не упомянул. Мне пока хватило инвалидации по таймауту и очистки кэша скриптом генерации public-версии (при изменениях в коде: рестарт апаче, сжатие js и css, пр.).
Но в перспективе - действительно надо :)
UPD: articles_cached[0].get_absolute_url()
тоже работает. так что он подымает полноценный объект.
кодит объекты перед укладкой в кэш он при помощи cPickle/pickle
Еще подумал: хорошо бы для кэширования запросов избавиться от явного использования API кэша.
Вот за пять минут накидал: chachedQuery.py
Хранит в кеше результаты запроса. Ключем является построенный sql запрос, вытаскиваемый из ихнего sql-построителя.
Пример там же.
зы: не забудьте сменить на девелоперской версии строку CACHE_BACKEND = 'dummy:///' на что-нить другое.
я минут 15 тупил че не работает... ;)
Да да, напишите про инвалидацию по сигналу. А то ведь комменты к посту в блоге тоже хочется кэшировать, но из надо как раз по добавлении нового коммента инвалидировать.

А на счет подключения разных конфигов, девелоперского и продакшн, я делаю проще. Просто from site_cfg import * в самом конце settings.py.

При этом site_cfg на каждой машинке свой и может переопределять любые опции из settings.py. Таким образом и конфиги разные, и пароль от базы данных в репозитории хранить не надо, что немаловажно если репозиторий публичный.
про инвалидацию:
я пока не нашел полностью устраивающего меня универсального решения. как найду - отпишусь.

на счет site_cfg:
а мне синковать (sync) удобнее, когда на всех машинах одно и тоже.
спасибо за статью!
пишите ещё у вас это хорошо получается :)
Спасибо за статью :)
Есть еще вариант, похожий на {% cache 500 sidebar %} - кэширование шаблонных тегов как функций. ИМХО это выглядит более логично.
может быть. но, по-моему, в кэш лучше положить отрендереный кусок нежели дамп объекта который будет каждый раз подыматься, по нему будешь бежать и вставлять куски маркапа... зачем? по мне код и так получается чистый и красивый - не надо бегать по всем пакам templatetags и смотреть не закэшировано ли где чего.
Идея в том, что основные тормоза порождает обращение к БД, рендеринг шаблона - мелочи. Поэтому как раз аккуратнее - указать, что кэшируются тяжелые функции, а не весь подряд шаблон.
Поделись своим опытом плз. Что у тебя бывает тормознее, чем обращение к БД и прочим внешним ресурсам? Неужели работа самого фреймворка?
Если база небольшая и правильно оптимизированная, то mysql отрабатывает за 0.001 секунд на простых выборках. А например фреймворки на пхп обычно генерят страницу в лучшем случае за 0.05 на том же железе. Особенно в пхп тормозят темплейтные движки (не считая Blitz, который на C). Насчет питона не знаю, не замерял пока, но даже если он быстрее пхп в разы, разница остается.

Кстати, а как Джанго обрабатывает темплейты? Кэшируется ли где-то результат их парсинга?
А, ты про пхп-шные фреймворки... Сорри, про них ничего не знаю. Пj нашим наблюдениям работы с Джангой, кэшировать работу питонских скриптов надо только с самом конце, когда все остальное уже оптимизировано вусмерть :)
И кстати еще аргумент: шаблоны и кэширование данных - настолько разные вещи, что лучше их не перемешивать.
да, Вы правы. только прейдется "бегать по всем пакам templatetags и смотреть не закэшировано ли где чего"...
Сорри, не понял, зачем "бегать по всем папкам templatetags"? При написании каждого тега можно решить, надо его кэшировать, или нет.
Я говорю с точки зрения поддержки. Например есть сайт, написанный другим человеком несколько месяцев назад. Моей целью является писать так, чтобы разабраться было как можно проще. Просмотрев шаблоны, благодаря наследованию и тегам джанги понять что откуда растет очень просто.

Наверное, кешированию не место в шаблонах. но за джанговцами вроде небыло замещено архитектурных просчетов. зачем они тогда его сделали в виде тега? ведь перемешивание MVC они предусмотрительно запретили... надо почитать дискуссии по этой фишке. ее ведь только что добавили в svnку
Точно также можно сказать "бегать по всем шаблонами смотреть не закэшировано ли где чего" :). Потому что кэширование может быть применено не только в базовом шаблоне, но и в потомках.
угу :) но по-моему шаблоны нагляднее. хотя если версаешь не ты сам...
UFO landed and left these words here
Что-то мне принцип не нравиться, так как параметры кеширования загоняются в сам шаблон. Если нужно поменять таймаут нужно лазить по всем шаблонам где используется данный фрагмент и его менять. Как-то нелогично получается. Да и засорять код всякими cache_ не считаю красивым, имхо удобнее выкинуть это в конфигурационные файлы.
Дак некто ж не мешает написать свой CONTEXT_PROCESSOR который будет загонять в переменные нужные времена.
Всё равно оно как-то непрозрачно, а написание отдельного костыля для вполне обыденной задачи тоже как-то не впечатляет. Я сужу только по этой статье, так что если я не прав - не пинайте сильно. Но всё равно, я за отделение конфигурации и кода, и всё-таки было бы лучше если бы фреймворк сам умел это делать.
как описать в настройках что хочешь закэшировать кусок шаблона?
лично у меня никаких идей. ориентироваться на имя блока? а если с параметрами? а если надо хранить несколько версий основываясь на контексте вызова?
Ну я ничего действительно универсального предложить не могу. Действительно подход указывания в шаблоне настроек кеша самый гибкий. Но тут ниже уже говорили, что верстальщикам такая радость не нужна.
Мне действительно кажеться логичнее задавать настройки кеша по имени фрагмента шаблона. Учитывая, что в Джанге есть их наследование, то "хранить несколько версий основываясь на контексте вызова". С параметрами система может кешировать и сама, искусственного интеллекта, чтоб создавать разные кеши под разные параметры не нужно.
UFO landed and left these words here
на счет таймаута согласен. вот хак - перекрыл стандартный тег cache чтоб он понимал, что если ему не дали таймаута первым параметром его надо взять из settings.py

кстати, чтобы не "лазить по всем шаблонам где используется данный фрагмент" нужно использовать наследование и определять блок один раз.

а на счет "засорения всякими cache_" - не согласен. по-моему там им самое место - сразу видишь что и где кэшируется. да и как описать в настройках что хочешь закэшировать кусок шаблона?
"по-моему там им самое место - сразу видишь что и где кэшируется."
Насколько я помню идеологию Джанги, шаблоны делают верстальщики. То есть те, кто не заморачивается за программную часть сайта. Поэтому думать про кэширование - не их компетенция.
действительно, как подумал что это попадется одному знакомому верстальщику - сразу захотелось спрятать кэширование куда-нить подальше... :))
Что-то я не очень понимаю.

<code>
{% block content %}
{{ tag.title }}
{{ tag.text }}
{% cache 500 article_list tag.id page %}
{{ block.super }}
{% endcache %}
{% endblock %}
</code>

Откуда именно здесь появляется список статей? Где именно написан код для доставания его из базы?
Нда, замороченый пример получился.
Ключевая строка - {{ block.super }}. Т.к. список статей и список статей имеющих определенный тег по шаблонам не отличаются я понаследовался от списка статей. Шаблон списка статей (из предыдущей статьи, этому будет равен {{ block.super }}):
{% for article in article_list %}
«a href="{% url article_view article.id %}"»
{{ article.title }}
«/a»
{% endfor %}
Тут тега нет т.к. список статей это основные данные отображения. Но по ленивой природе запросов в бд в django запрос в базу не идет.

Если упростить, то отображения для них будут такими:
@render_to('blog/index.htm')
def index(request):
article_list=Article.objects.filter(public=True)
return {
'article_list': article_list,
}

@render_to('blog/tag_index.htm')
def tag(request, tag_slug):
tag=get_object_or_404(Tag, slug=tag_slug)
article_list=Article.objects.filter(tags=tag, public=True)
return {
'tag': tag,
'article_list': article_list,
}
Значит, я правильно понимаю, что фактически исполнение кода article_list=Article.objects.filter(tags=tag, public=True) происходит только когда в шаблоне происходит {% for article in article_list %}?
да. article_list это объект типа QuerySet. запрос в базу отрпавляется при первом обращении к данным (в частности, при итерировании).
Ага, вот мы и подобрались к тому, о чем моя заметка. ;-) Что, если article_list - не QuerySet, а результат нескольких запросов, да еще и обработанных программой? Автоматически ленивая загрузка тут может не получиться. И именно в таком случае и пригождается возможность подготовить операцию, не выполняя ее.
Ленивая загрузка коллекций у меня тоже есть, но не всегда удается обойтись автоматикой.
тут примерчик явного кэширования запроса. если совсем немного доточить, то можно хранить что угодно.

на самом деле решение предложенного вами примера не очень корректено. article_list - это основные и единственные данные страницы. если нельзя кэшировать всю страницу, то можно вынести их в тег и кэшировать его (при помощи cache_page). получится неленивая загрузка, но код будет выполняться только если данных нет в кэше.
Спасибо, интересно. Мне только непонятно зачем нужны таймауты. Как по мне, гораздо логичнее сделать таймаут бесконечным и инвалидировать кэш программно при фактическом изменении данных. Возможно ли это в Django?
Согласен. Это просто самое простое решение. В джанге есть сигналы. Можно повесить событие например на сохранение объекта. и в этом событии инвалидировать кэш связанный с сохраненным объектом. вот только если объект встречается во многих местах, то найти и инвалидировать все его кэши не такая тривиальная задача.
Радует что есть такое. Буду курить доку. :) Вообще я только начал изучать питон и джанго и не могу нарадоваться какой это офигенный фреймворк. В нем есть всё что я долго и безуспешно искал во фреймворках на пхп. Причем на пхп вся эта красота врядли возможна в принципе.
Да.. Осталось добавить настоящую объектность (классы, функции итд как объекты), указание имен параметров при вызове функций, подключения модуля как неймспейс, итераторы, декораторы, генераторы и всё остальное... И получится Питон. :)
Имхо, это ещё тот пример где фреймворки на РНР выглядят достойно :)
Вот это, по-моему, самое интересное: как привязать используемые объекты к элементам кэша и инвалидировать только то, что действительно изменилось.
Only those users with full accounts are able to leave comments. Log in, please.