-
Хочу вот закешировать несколько тегов с помощью декоратора, тег, например, такой:
Когда добавляю к нему @cache_page получаю ошибку@register.inclusion_tag('tags/user_rating_tag.html',takes_context=True)
def user_rating(context):
from django.contrib.auth.models import User
users = User.objects.extra(select={'title':"news.title",'cnt':'COUNT(*)'},
tables =['news'],
where=['news.user_id=auth_user.id GROUP BY auth_user.username']
).order_by('-cnt')
return {
'users':users,
'MEDIA_URL':context['MEDIA_URL']
}
Кстати, я может неправильно понял кеширование вообще - если я ставлю кеш на вьюшку которая рендерит страницу с указанными тегами, то может мне их кешировать не надо?TemplateSyntaxError at /
Any tag function decorated with takes_context=True must have a first argument of 'context' -
cache_page кеширует страницу, а не тег, согласись...что-то в названии декоратора об этом говорит....
кешировать отдельные теги, как мне кажется, не нужно. -
О! Это мой любимый вопрос в последнее время :-)
К сожалению, с декорированием inclusion_ и simple_tag в Джанго проблемы, потому что юзерский декоратор практически всегда замешивает аргументы декорируемой функции в "*args, **kwargs" (что естественно), а джанговские теговые декораторы хотят видеть первоначальные имена параметров.
Есть и еще одна проблема, на первый взгляд мелкая, но вот в нашем проекте вставшая неожиданно остро. Мы сначала вытащили все "мясо" тега в отдельную функцию и кешировали ее (некрасиво, но работает):
Но этого оказалось недостаточно, потому что таким образом кешируется только создание данных для включаемого шаблона, но не рендеринг их в HTML. Причем у нас в проекте на индексной странице, загруженной такими включаемыми информерами, если HTML закешировать, скорость растет раза в полтора. Поэтому я в итоге написал свой аналог inclusion_tag'а. Если интересно, могу сюда его скинуть в понедельник.@cached
def _some_tag(context):
return {...}
@register.inclusion_tag('template.html', takes_context=True)
def some_tag(context):
return _some_tag(context) -
Скинь пожалуйста, потому что ситуация (информеры) абсолютно такая же :)
-
Код такой:
Используется примерно так:def cached(key_func, timeout=settings.CACHE_TIMEOUT):
'''
Кеширующий декоратор.
'''
def decorator(func):
def wrapper(*args, **kwargs):
key = str(key_func(*args, **kwargs))
value = cache.get(key)
if value is None:
value = func(*args, **kwargs)
cache.set(key, value, timeout)
return value
wrapper.__name__ = func.__name__
return wrapper
return decorator
class InformerNode(template.Node):
'''
Информер -- inclusion-тег для шаблона, который все данные для себя принимает
из контекста и умеет кешироваться.
func: функция, расчитывающая внутренний контекст
template_name: имя включаемого шаблона
cached_key_func: функция, примающая контекст и формирующая ключ
'''
def __init__(self, func, template_name, cache_key_func):
self.func = func
if cache_key_func:
self.render = cached(cache_key_func)(self.render)
self.template_name = template_name
def render(self, context):
t = loader.get_template(self.template_name)
return t.render(Context(self.func(context)))
def informer(template_name, cache_key_func=None):
'''
Декоратор, делающий из функции подготовки контекста для информера, функцию,
пригодную для регистрации в качестве тега
'''
def decorator(func):
def wrapper(parser, token):
return InformerNode(func, template_name, cache_key_func)
wrapper._decorated_func = func
wrapper.__name__ = func.__name__
return wrapper
return decorator
Единственная необычность — это lambda, принимающая контекст в параметре информера. Она должна вернуть строчку ключа кеша, в котором информер хранить. В прстейшем случае, если информер одинаков на всех страницах, это будет просто константа типа "lambda c: 'myinformer'". Если зависит от имени юзера, напрмер, то "lambda c: ;myinformer-' + c['user'].username". Ну и в таком духе.@register.tag
@informer('template.html', lambda c: ....)
def my_tag(context):
return {
'value': value,
} -
Спасибо большое, буду применять!
-
А вот еще вопрос, как работать с кешем, когда большая часть страницы, которая кешируется, изменилась, можно ли как-то сказать джанге очистить и сгенерить его заново?
-
Хм, у меня с этим тегом скорость еще меньше чем без кеширования, странно очень. Использую пока дисковый кеш.
-
А чего не memcached? У меня прирост был как раз из-за того, что я сэкономил на всяких loader.get_template, которые файлы с диска читают.
-
Он на подходе, никак саппорт не поставит (сам я могу, но такая ситуация). Хотя если он будет еще шустрее чем дисковый, то вообще сказка :))
Пока же остановился на схеме CacheMiddleware для анонимов, и внутри на твоем теге сделаны редко изменяющиеся блоки. На анониме выходит 200 запросов в секунду, на залогиненом (там большая часть страницы меняется активно, поэтому кешировать все не выходит) - 25-50. В принципе я доволен :) -
О, да, это совсем неплохо :-)
-
на анониме должна быть 1000 запросов/сек с сервером 1GHz/1Gb. тогда можно работать.
-
Даже у twitter 600, а у меня загрузка 30-40К просмотров в день :)
-
Кстати в воскресенье в джангу добавили кеширующий тег, для части шаблона, очень полезная штука.
http://www.djangoproject.com/documentation/cache/#template-fragment-caching -
Да, приятная штука! Сойдет там, где кеш только по времени протухает.
-
а что изменилось в джанге со времени написания данного поста — в плане Кеширование inclusion tags
ЗЫ
а данный форум не шлет уведомления на почту о новых комментариях?
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.



