Комментарии 51
При включенном кэшировании всего сайта часто бывает полезно поставить CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
чтобы включить полный кэш для анонимов, а для остальных использовать блочное/per-view кэширование.
чтобы включить полный кэш для анонимов, а для остальных использовать блочное/per-view кэширование.
Еще интересное - это кэширование 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, пр.).
Но в перспективе - действительно надо :)
Для кэширования 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
тоже работает. так что он подымает полноценный объект.
кодит объекты перед укладкой в кэш он при помощи cPickle/pickle
Еще подумал: хорошо бы для кэширования запросов избавиться от явного использования API кэша.
Вот за пять минут накидал: chachedQuery.py
Хранит в кеше результаты запроса. Ключем является построенный sql запрос, вытаскиваемый из ихнего sql-построителя.
Пример там же.
Вот за пять минут накидал: chachedQuery.py
Хранит в кеше результаты запроса. Ключем является построенный sql запрос, вытаскиваемый из ихнего sql-построителя.
Пример там же.
зы: не забудьте сменить на девелоперской версии строку CACHE_BACKEND = 'dummy:///' на что-нить другое.
я минут 15 тупил че не работает... ;)
я минут 15 тупил че не работает... ;)
очепятался: cachedQuery.py
Да да, напишите про инвалидацию по сигналу. А то ведь комменты к посту в блоге тоже хочется кэшировать, но из надо как раз по добавлении нового коммента инвалидировать.
А на счет подключения разных конфигов, девелоперского и продакшн, я делаю проще. Просто from site_cfg import * в самом конце settings.py.
При этом site_cfg на каждой машинке свой и может переопределять любые опции из settings.py. Таким образом и конфиги разные, и пароль от базы данных в репозитории хранить не надо, что немаловажно если репозиторий публичный.
А на счет подключения разных конфигов, девелоперского и продакшн, я делаю проще. Просто from site_cfg import * в самом конце settings.py.
При этом site_cfg на каждой машинке свой и может переопределять любые опции из settings.py. Таким образом и конфиги разные, и пароль от базы данных в репозитории хранить не надо, что немаловажно если репозиторий публичный.
спасибо за статью!
пишите ещё у вас это хорошо получается :)
пишите ещё у вас это хорошо получается :)
Отличная статья, спасибо, ждем еще :)
Спасибо за статью :)
Есть еще вариант, похожий на {% cache 500 sidebar %} - кэширование шаблонных тегов как функций. ИМХО это выглядит более логично.
Есть еще вариант, похожий на {% cache 500 sidebar %} - кэширование шаблонных тегов как функций. ИМХО это выглядит более логично.
может быть. но, по-моему, в кэш лучше положить отрендереный кусок нежели дамп объекта который будет каждый раз подыматься, по нему будешь бежать и вставлять куски маркапа... зачем? по мне код и так получается чистый и красивый - не надо бегать по всем пакам templatetags и смотреть не закэшировано ли где чего.
Идея в том, что основные тормоза порождает обращение к БД, рендеринг шаблона - мелочи. Поэтому как раз аккуратнее - указать, что кэшируются тяжелые функции, а не весь подряд шаблон.
Бывает так конечно, но мягко говоря - не всегда.
Поделись своим опытом плз. Что у тебя бывает тормознее, чем обращение к БД и прочим внешним ресурсам? Неужели работа самого фреймворка?
Если база небольшая и правильно оптимизированная, то mysql отрабатывает за 0.001 секунд на простых выборках. А например фреймворки на пхп обычно генерят страницу в лучшем случае за 0.05 на том же железе. Особенно в пхп тормозят темплейтные движки (не считая Blitz, который на C). Насчет питона не знаю, не замерял пока, но даже если он быстрее пхп в разы, разница остается.
Кстати, а как Джанго обрабатывает темплейты? Кэшируется ли где-то результат их парсинга?
Кстати, а как Джанго обрабатывает темплейты? Кэшируется ли где-то результат их парсинга?
И кстати еще аргумент: шаблоны и кэширование данных - настолько разные вещи, что лучше их не перемешивать.
да, Вы правы. только прейдется "бегать по всем пакам templatetags и смотреть не закэшировано ли где чего"...
Сорри, не понял, зачем "бегать по всем папкам templatetags"? При написании каждого тега можно решить, надо его кэшировать, или нет.
Я говорю с точки зрения поддержки. Например есть сайт, написанный другим человеком несколько месяцев назад. Моей целью является писать так, чтобы разабраться было как можно проще. Просмотрев шаблоны, благодаря наследованию и тегам джанги понять что откуда растет очень просто.
Наверное, кешированию не место в шаблонах. но за джанговцами вроде небыло замещено архитектурных просчетов. зачем они тогда его сделали в виде тега? ведь перемешивание MVC они предусмотрительно запретили... надо почитать дискуссии по этой фишке. ее ведь только что добавили в svnку
Наверное, кешированию не место в шаблонах. но за джанговцами вроде небыло замещено архитектурных просчетов. зачем они тогда его сделали в виде тега? ведь перемешивание MVC они предусмотрительно запретили... надо почитать дискуссии по этой фишке. ее ведь только что добавили в svnку
Что-то мне принцип не нравиться, так как параметры кеширования загоняются в сам шаблон. Если нужно поменять таймаут нужно лазить по всем шаблонам где используется данный фрагмент и его менять. Как-то нелогично получается. Да и засорять код всякими cache_ не считаю красивым, имхо удобнее выкинуть это в конфигурационные файлы.
Дак некто ж не мешает написать свой CONTEXT_PROCESSOR который будет загонять в переменные нужные времена.
Всё равно оно как-то непрозрачно, а написание отдельного костыля для вполне обыденной задачи тоже как-то не впечатляет. Я сужу только по этой статье, так что если я не прав - не пинайте сильно. Но всё равно, я за отделение конфигурации и кода, и всё-таки было бы лучше если бы фреймворк сам умел это делать.
как описать в настройках что хочешь закэшировать кусок шаблона?
лично у меня никаких идей. ориентироваться на имя блока? а если с параметрами? а если надо хранить несколько версий основываясь на контексте вызова?
лично у меня никаких идей. ориентироваться на имя блока? а если с параметрами? а если надо хранить несколько версий основываясь на контексте вызова?
Ну я ничего действительно универсального предложить не могу. Действительно подход указывания в шаблоне настроек кеша самый гибкий. Но тут ниже уже говорили, что верстальщикам такая радость не нужна.
Мне действительно кажеться логичнее задавать настройки кеша по имени фрагмента шаблона. Учитывая, что в Джанге есть их наследование, то "хранить несколько версий основываясь на контексте вызова". С параметрами система может кешировать и сама, искусственного интеллекта, чтоб создавать разные кеши под разные параметры не нужно.
Мне действительно кажеться логичнее задавать настройки кеша по имени фрагмента шаблона. Учитывая, что в Джанге есть их наследование, то "хранить несколько версий основываясь на контексте вызова". С параметрами система может кешировать и сама, искусственного интеллекта, чтоб создавать разные кеши под разные параметры не нужно.
НЛО прилетело и опубликовало эту надпись здесь
на счет таймаута согласен. вот хак - перекрыл стандартный тег cache чтоб он понимал, что если ему не дали таймаута первым параметром его надо взять из settings.py
кстати, чтобы не "лазить по всем шаблонам где используется данный фрагмент" нужно использовать наследование и определять блок один раз.
а на счет "засорения всякими cache_" - не согласен. по-моему там им самое место - сразу видишь что и где кэшируется. да и как описать в настройках что хочешь закэшировать кусок шаблона?
кстати, чтобы не "лазить по всем шаблонам где используется данный фрагмент" нужно использовать наследование и определять блок один раз.
а на счет "засорения всякими 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,
}
Ключевая строка - {{ 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). получится неленивая загрузка, но код будет выполняться только если данных нет в кэше.
на самом деле решение предложенного вами примера не очень корректено. article_list - это основные и единственные данные страницы. если нельзя кэшировать всю страницу, то можно вынести их в тег и кэшировать его (при помощи cache_page). получится неленивая загрузка, но код будет выполняться только если данных нет в кэше.
Спасибо, интересно. Мне только непонятно зачем нужны таймауты. Как по мне, гораздо логичнее сделать таймаут бесконечным и инвалидировать кэш программно при фактическом изменении данных. Возможно ли это в Django?
Согласен. Это просто самое простое решение. В джанге есть сигналы. Можно повесить событие например на сохранение объекта. и в этом событии инвалидировать кэш связанный с сохраненным объектом. вот только если объект встречается во многих местах, то найти и инвалидировать все его кэши не такая тривиальная задача.
Радует что есть такое. Буду курить доку. :) Вообще я только начал изучать питон и джанго и не могу нарадоваться какой это офигенный фреймворк. В нем есть всё что я долго и безуспешно искал во фреймворках на пхп. Причем на пхп вся эта красота врядли возможна в принципе.
Имхо, это ещё тот пример где фреймворки на РНР выглядят достойно :)
Вот это, по-моему, самое интересное: как привязать используемые объекты к элементам кэша и инвалидировать только то, что действительно изменилось.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Кэширование в Django