from catalogue.models.tag import prefetched_relations
from catalogue import app_settings
from catalogue import tasks
-from wolnelektury.utils import makedirs
+from wolnelektury.utils import makedirs, cached_render, clear_cached_renders
bofh_storage = BofhFileSystemStorage()
parent = parent.parent
def flush_includes(self, languages=True):
+ clear_cached_renders(self.mini_box)
+ clear_cached_renders(self.mini_box_nolink)
if not languages:
return
if languages is True:
flush_ssi_includes([
template % (self.pk, lang)
for template in [
- '/katalog/b/%d/mini.%s.html',
- '/katalog/b/%d/mini_nolink.%s.html',
'/katalog/b/%d/short.%s.html',
'/katalog/b/%d/wide.%s.html',
'/api/include/book/%d.%s.json',
def cover_color(self):
return WLCover.epoch_colors.get(self.extra_info.get('epoch'), '#000000')
+ @cached_render('catalogue/book_mini_box.html')
+ def mini_box(self):
+ return {
+ 'book': self
+ }
+
+ @cached_render('catalogue/book_mini_box.html')
+ def mini_box_nolink(self):
+ return {
+ 'book': self,
+ 'no_link': True,
+ }
def add_file_fields():
for format_ in Book.formats:
{% extends "base/base.html" %}
{% load i18n %}
-{% load common_tags catalogue_tags %}
+{% load catalogue_tags %}
{% load build_absolute_uri from fnp_common %}
{% load cache %}
<section class="see-also">
<h1>{% trans "Other versions" %}:</h1>
{% for rel in book.other_versions %}
- {% cache 86400 book_mini_box rel.pk %}
- {% include 'catalogue/book_mini_box.html' with book=rel %}
- {% endcache %}
+ {{ rel.mini_box }}
{% endfor %}
</section>
{% endif %}
{% extends "base/base.html" %}
{% load i18n %}
{% load catalogue_tags %}
-{% load ssi_include from ssify %}
+{% load chunk from chunks %}
{% block bodyid %}book-a-list{% endblock %}
<div class="left-column"><div class="normal-text" style="margin-bottom: 2em">
{% block book_list_info %}
- {% ssi_include 'chunk' key='book-list' %}
+ {% chunk 'book-list' %}
{% endblock %}
</div></div>
{% extends "catalogue/viewer_base.html" %}
{% load i18n %}
-{% load catalogue_tags ssify %}
+{% load catalogue_tags %}
{% load thumbnail %}
-{% load cache %}
{% block title %}{{ book.pretty_title }}{% endblock %}
{% block big-pane %}
<article id="main-text">
- <!--#include file='{{ book.html_url }}' -->
+ {{ book.html_file.read|safe }}
</article>
<article id="other-text">
<a class="display-other"
data-other="{{ other_version.html_url }}"
href="{% url 'book_text' other_version.slug %}">
- {% cache 86400 book_mini_box other_version.pk %}
- {% include 'catalogue/book_mini_box.html' with book=other_version no_link=True %}
- {% endcache %}
+ {{ other_version.mini_box_nolink }}
</a>
</li>
{% endfor %}
{% spaceless %}
{% load i18n %}
- {% load ssi_include from ssify %}
- {% load cache %}
<div class="collection-box white-box">
<h2><a href="{{ collection.get_absolute_url }}">{% trans "Collection" %}: {{ collection }}</a></h2>
{% if collection.description %}
{{ collection.description|safe|truncatewords_html:40 }}
{% endif %}
{% for book in collection.get_books|slice:":5" %}
- {% cache 86400 book_mini_box book.pk %}
- {% include 'catalogue/book_mini_box.html' %}
- {% endcache %}
+ {{ book.mini_box }}
{% endfor %}
{% with collection.get_books.count|add:-5 as more %}
{% if more > 0 %}
{% extends "catalogue/book_list.html" %}
{% load i18n %}
-{% load ssi_include from ssify %}
+{% load chunk from chunks %}
{% block bodyid %}book-a-list{% endblock %}
{% block book_list_header %}{% trans "Listing of all DAISY files" %}{% endblock %}
{% block book_list_info %}
- {% ssi_include 'chunk' key='daisy-list' %}
+ {% chunk 'daisy-list' %}
{% endblock %}
{% spaceless %}
{% load catalogue_random_book from catalogue_tags %}
{% load picture_random_picture from picture_tags %}
- {% load ssi_include from ssify %}
- {% load cache %}
{% for pic in pics %}
- {% ssi_include 'picture_mini' pk=pic.pk %}
+ {{ pic.mini_box }}
{% endfor %}
{% for book in books %}
- {% cache 86400 book_mini_box book.pk %}
- {% include 'catalogue/book_mini_box.html' %}
- {% endcache %}
+ {{ book.mini_box }}
{% endfor %}
{% if random %}
- {% catalogue_random_book random_excluded_books as random_book_pk %}
- {% picture_random_picture random_excluded_pics unless=random_book_pk as random_pic_pk %}
- {{ random_book_pk.if }}
- {% ssi_include 'catalogue_book_mini' pk=random_book_pk %}
- {{ random_book_pk.endif }}
- {{ random_pic_pk.if }}
- {% ssi_include 'picture_mini' pk=random_pic_pk %}
- {{ random_pic_pk.endif }}
+ {% catalogue_random_book random_excluded_books as random_book %}
+ {% picture_random_picture random_excluded_pics unless=random_book as random_pic %}
+ {% if random_book %}
+ {{ random_book.mini_box }}
+ {% endif %}
+ {% if random_pic %}
+ {{ random_pic.mini_box }}
+ {% endif %}
{% endif %}
{% endspaceless %}
{% extends "base/base.html" %}
{% load i18n %}
{% load catalogue_tags switch_tag social_tags %}
-{% load ssi_include from ssify %}
{% block titleextra %}{% if tags %}{% title_from_tags tags %}{% elif list_type == 'gallery' %}{% trans "Gallery" %}{% elif list_type == 'audiobooks' %}{% trans "Audiobooks" %}{% else %}{% trans "Literature" %}{% endif %}{% endblock %}
{% endif %}
</div>
- {% comment %}
- {% if list_type == 'books' and not tags %}
- <section>
- <h1>{% trans "Recent publications" %}</h1>
- {% for book in last_published %}
- {% ssi_include 'catalogue_book_mini' pk=book.pk %}
- {% endfor %}
- <a class="more" href="{% url 'recent_list' %}">{% trans "More recent publications" %}</a>
- </section>
- <section>
- <h1>{% trans "Most popular books" %}</h1>
- {% for book in most_popular %}
- {% ssi_include 'catalogue_book_mini' pk=book.pk %}
- {% endfor %}
- </section>
- {% endif %}
- {% endcomment %}
-
{% if theme_is_set %}
{% work_list object_list %}
{% else %}
return source.name or netloc
-@ssi_variable(register, patch_response=[add_never_cache_headers])
-def catalogue_random_book(request, exclude_ids):
+@register.simple_tag
+def catalogue_random_book(exclude_ids):
from .. import app_settings
if random() < app_settings.RELATED_RANDOM_PICTURE_CHANCE:
+ print('yay, picture')
return None
queryset = Book.objects.exclude(pk__in=exclude_ids)
count = queryset.count()
if count:
- return queryset[randint(0, count - 1)].pk
+ return queryset[randint(0, count - 1)]
else:
return None
'daisy/',
# 'autor/jane-doe/gatunek/genre/',
# 'autor/jane-doe/gatunek/genre/motyw/sielanka/',
- 'b/%d/mini.pl.html' % self.book.pk,
- 'b/%d/mini_nolink.pl.html' % self.book.pk,
'b/%d/short.pl.html' % self.book.pk,
'b/%d/wide.pl.html' % self.book.pk,
'f/%d/promo.pl.html' % self.book.fragments.all()[0].pk,
'autor/nonexistent/', # Nonexistent author.
'motyw/nonexistent/', # Nonexistent theme.
'zh.json', # Nonexistent language.
- 'b/%d/mini.pl.html' % (self.book.pk + 100), # Nonexistent book.
- 'b/%d/mini_nolink.pl.html' % (self.book.pk + 100), # Nonexistent book.
'b/%d/short.pl.html' % (self.book.pk + 100), # Nonexistent book.
'b/%d/wide.pl.html' % (self.book.pk + 100), # Nonexistent book.
'f/%d/promo.pl.html' % (self.book.fragments.all()[0].pk + 100), # Nonexistent fragment.
url(r'^obraz/(?P<slug>%s).html$' % SLUG, picture.views.picture_viewer, name='picture_viewer'),
url(r'^obraz/(?P<slug>%s)/$' % SLUG, picture.views.picture_detail, name='picture_detail'),
- url(r'^p/(?P<pk>\d+)/mini\.(?P<lang>.+)\.html', picture.views.picture_mini, name='picture_mini'),
url(r'^p/(?P<pk>\d+)/short\.(?P<lang>.+)\.html', picture.views.picture_short, name='picture_short'),
url(r'^pa/(?P<pk>\d+)/short\.(?P<lang>.+)\.html', picture.views.picturearea_short, name='picture_area_short'),
url(r'^isbn/(?P<book_format>(pdf|epub|mobi|txt|html))/(?P<slug>%s)/' % SLUG, views.get_isbn),
# Includes.
- url(r'^b/(?P<pk>\d+)/mini\.(?P<lang>.+)\.html', views.book_mini, name='catalogue_book_mini'),
- url(r'^b/(?P<pk>\d+)/mini_nolink\.(?P<lang>.+)\.html', views.book_mini, {'with_link': False},
- name='catalogue_book_mini_nolink'),
url(r'^b/(?P<pk>\d+)/short\.(?P<lang>.+)\.html', views.book_short, name='catalogue_book_short'),
url(r'^b/(?P<pk>\d+)/wide\.(?P<lang>.+)\.html', views.book_wide, name='catalogue_book_wide'),
url(r'^f/(?P<pk>\d+)/promo\.(?P<lang>.+)\.html', views.fragment_promo, name='catalogue_fragment_promo'),
})
+@never_cache
def book_detail(request, slug):
try:
book = Book.objects.get(slug=slug)
####
-@ssi_included
-def book_mini(request, pk, with_link=True):
- # book = get_object_or_404(Book, pk=pk)
- try:
- book = Book.objects.only('cover_thumb', 'title', 'language', 'slug').get(pk=pk)
- except Book.DoesNotExist:
- raise Http404
- return render(request, 'catalogue/book_mini_box.html', {
- 'book': book,
- 'no_link': not with_link,
- })
-
-
@ssi_included(get_ssi_vars=lambda pk: (lambda ipk: (
('ssify.get_csrf_token',),
('social_tags.likes_book', (ipk,)),
-# -*- coding: utf-8 -*-
# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from django.conf import settings
+from django.core.cache import cache
from django.db import models
from django.utils.translation import ugettext_lazy as _
-from ssify import flush_ssi_includes
class Chunk(models.Model):
def save(self, *args, **kwargs):
ret = super(Chunk, self).save(*args, **kwargs)
- self.flush_includes()
+ for lc, ln in settings.LANGUAGES:
+ cache.delete('chunk:%s:%s' % (self.key, lc))
return ret
- def flush_includes(self):
- flush_ssi_includes([
- '/chunks/chunk/%s.%s.html' % (self.key, lang)
- for lang in [lc for (lc, _ln) in settings.LANGUAGES]])
-
class Attachment(models.Model):
key = models.CharField(_('key'), help_text=_('A unique name for this attachment'), primary_key=True, max_length=255)
-# -*- coding: utf-8 -*-
from django import template
from django.core.cache import cache
from django.utils.safestring import mark_safe
+from django.utils.translation import get_language
from ..models import Chunk, Attachment
@register.simple_tag
def chunk(key, cache_time=0):
try:
- cache_key = 'chunk_' + key
+ cache_key = 'chunk:%s:%s' % (key, get_language())
c = cache.get(cache_key)
if c is None:
c = Chunk.objects.get(key=key)
+++ /dev/null
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.conf.urls import url
-from . import views
-
-
-urlpatterns = [
- url(r'^chunk/(?P<key>.+)\.(?P<lang>.+)\.html$', views.chunk, name='chunk'),
-]
+++ /dev/null
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.http import HttpResponse
-from ssify import ssi_included
-from .models import Chunk
-
-
-@ssi_included
-def chunk(request, key):
- chunk, created = Chunk.objects.get_or_create(key=key)
- return HttpResponse(chunk.content)
from catalogue.models.tag import prefetched_relations
from catalogue.utils import split_tags
from picture import tasks
+from wolnelektury.utils import cached_render, clear_cached_renders
from io import BytesIO
import jsonfield
import itertools
names = [tag[0] for tag in names]
return ', '.join(names)
+ @cached_render('picture/picture_mini_box.html')
+ def mini_box(self):
+ return {
+ 'picture': self,
+ }
+
def related_themes(self):
return catalogue.models.Tag.objects.usage_for_queryset(
self.areas.all(), counts=True).filter(category__in=('theme', 'thing'))
def flush_includes(self, languages=True):
+ clear_cached_renders(self.mini_box)
if not languages:
return
if languages is True:
{% load i18n %}
{% load catalogue_tags %}
{% load static %}
-{% load ssi_include from ssify %}
+{% load chunk from chunks %}
{% block bodyid %}picture-list{% endblock %}
<div class="left-column">
<div class="normal-text">
{% block book_list_info %}
- {% ssi_include 'chunk' key='picture-list' %}
+ {% chunk 'picture-list' %}
{% endblock %}
</div>
</div>
{% spaceless %}
{% load thumbnail %}
+ {% with picture.author_unicode as author %}
<div class="book-mini-box">
<div class="book-mini-box-inner">
- {% if with_link %}
<a href="{{ picture.get_absolute_url }}">
- {% endif %}
{% if picture.image_file %}
<img src="{% thumbnail picture.image_file "139x193" crop="center" as thumb %}{{ thumb.url }}{% empty %}{{ picture.image_file.url }}{% endthumbnail %}" alt="{{ author }} – {{ picture.title }}" class="cover" />
{% endif %}
<span class="mono author">{{ author }}</span>
<span class="title">{{ picture.title }}</span>
</div>
- {% if with_link %}
</a>
- {% endif %}
</div>
</div>
-{% endspaceless %}
\ No newline at end of file
+ {% endwith %}
+{% endspaceless %}
from django.urls import reverse
from django.utils.cache import add_never_cache_headers
import sorl.thumbnail.default
-from ssify import ssi_variable
from catalogue.utils import split_tags
from ..engine import CustomCroppingEngine
from ..models import Picture
return th.url
-@ssi_variable(register, patch_response=[add_never_cache_headers])
-def picture_random_picture(request, exclude_ids, unless=None):
+@register.simple_tag
+def picture_random_picture(exclude_ids, unless=None):
if unless:
return None
queryset = Picture.objects.exclude(pk__in=exclude_ids).exclude(image_file='')
count = queryset.count()
if count:
- return queryset[randint(0, count - 1)].pk
+ return queryset[randint(0, count - 1)]
else:
return None
return HttpResponse(_("Error importing file: %r") % import_form.errors)
-@ssi_included
-def picture_mini(request, pk, with_link=True):
- picture = get_object_or_404(Picture, pk=pk)
- return render(request, 'picture/picture_mini_box.html', {
- 'picture': picture,
- 'author': picture.author_unicode(),
- 'with_link': with_link,
- })
-
-
@ssi_included
def picture_short(request, pk):
picture = get_object_or_404(Picture, pk=pk)
-# -*- coding: utf-8 -*-
# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
import json
import time
from io import BytesIO
+from django.core.cache import cache
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
from jsonfield import JSONField
from django.core.files.base import ContentFile
-from ssify import flush_ssi_includes
THUMB_WIDTH = 120
THUMB_HEIGHT = 120
'page': self
})
ret = super(SponsorPage, self).save(*args, **kwargs)
- self.flush_includes()
+ cache.delete('sponsor_page:' + name)
return ret
- def flush_includes(self):
- flush_ssi_includes(['/sponsors/page/%s.html' % self.name])
-
def __str__(self):
return self.name
--- /dev/null
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django import template
+from django.core.cache import cache
+from django.utils.safestring import mark_safe
+from sponsors.models import SponsorPage
+
+
+register = template.Library()
+
+
+@register.simple_tag
+def sponsor_page(name):
+ key = 'sponsor_page:' + name
+ content = cache.get(key)
+ if content is None:
+ try:
+ page = SponsorPage.objects.get(name=name)
+ except SponsorPage.DoesNotExist:
+ content = ''
+ else:
+ content = page.html
+ cache.set(key, content)
+ return mark_safe(content)
+++ /dev/null
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.conf.urls import url
-from . import views
-
-
-urlpatterns = [
- url(r'^page/(?P<name>.+)\.html$', views.page, name='sponsor_page'),
-]
+++ /dev/null
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.http import HttpResponse
-from ssify import ssi_included
-from .models import SponsorPage
-
-
-@ssi_included(use_lang=False)
-def page(request, name):
- try:
- page = SponsorPage.objects.get(name=name)
- except SponsorPage.DoesNotExist:
- return HttpResponse(u'')
- return HttpResponse(page.html)
<html lang="{{ LANGUAGE_CODE }}" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
{% load pipeline i18n %}
{% load static from staticfiles %}
- {% load catalogue_tags funding_tags reporting_stats %}
{% load piwik_tags %}
- {% load ssi_include from ssify %}
- {% load user_username user_is_staff from common_tags %}
- {% load cache %}
{% get_current_language as LANGUAGE_CODE %}
<head>
<meta charset="utf-8">
<nav id="menu">
<ul id="user-info">
- {% user_username as user_username %}
- {% user_is_staff as user_is_staff %}
- {{ user_username.if }}
+ {% if request.user.is_authenticated %}
<li>
<a href="{% url 'user_settings' %}">
<strong>{{ user_username }}</strong>
</a>
</li>
- {{ user_username.endif }}
- {{ user_username.if }}
<li>
<a href="{% url 'logout' %}?next={% block logout %}{{ request.get_full_path }}{% endblock %}">{% trans "Logout" %}</a>
</li>
- {{ user_username.endif }}
+ {% endif %}
</ul>
</nav>
{% load static from staticfiles %}
{% load catalogue_tags funding_tags reporting_stats %}
{% load piwik_tags %}
- {% load ssi_include from ssify %}
- {% load user_username user_is_staff from common_tags %}
{% load cache %}
+ {% load chunk from chunks %}
+ {% load sponsor_page from sponsors %}
{% get_current_language as LANGUAGE_CODE %}
<head>
<meta charset="utf-8">
<a id="show-menu"></a>
<nav id="menu">
<ul id="user-info">
- {% user_username as user_username %}
- {% user_is_staff as user_is_staff %}
- {{ user_username.if }}
+ {% if request.user.is_authenticated %}
<li>
<a href="{% url 'user_settings' %}">
- <strong>{{ user_username }}</strong>
+ <strong>{{ request.user.username }}</strong>
</a>
</li>
<li>
<a href="{% url 'social_my_shelf' %}" id="user-shelves-link">{% trans "My shelf" %}</a>
</li>
- {{ user_username.endif }}
- {{ user_is_staff.if }}
- <li><a href="{% url 'admin:index' %}">{% trans "Administration" %}</a></li>
- {{ user_is_staff.endif }}
- {{ user_username.if }}
+ {% if request.user.is_staff %}
+ <li><a href="{% url 'admin:index' %}">{% trans "Administration" %}</a></li>
+ {% endif %}
<li>
<a href="{% url 'logout' %}?next={% block logout %}{{ request.get_full_path }}{% endblock %}">{% trans "Logout" %}</a>
</li>
- {{ user_username.else }}
+ {% else %}
<li>
<a href="{% url 'login' %}?next={{ request.path }}" id="login">{% trans "Sign in" %}</a>
/ <a href="{% url 'register' %}?next={{ request.path }}" id="register">{% trans "Register" %}</a>
</li>
- {{ user_username.endif }}
+ {% endif %}
</ul>
<ul id="main-menu">
<div id="footer-wrapper">
<footer id="main">
- {% ssi_include 'chunk' key='footer' %}
+ {% chunk 'footer' %}
{% block add_footer %}{% endblock %}
- {% ssi_include 'sponsor_page' name='footer' %}
+ {% sponsor_page 'footer' %}
</footer>
</div>
<div class="main-library-row">
<div class="covers">
{% for book in best %}
- {% cache 86400 book_mini_box book.pk %}
- {% include 'catalogue/book_mini_box.html' %}
- {% endcache %}
+ {{ book.mini_box }}
{% endfor %}
</div>
<a href="{% url "book_list" %}">
<h2>{% trans "Theme" %}: {{ theme }}</h2>
<p>{% trans "Explore works with the same theme" %}</p>
{% for book in theme_books %}
- {% cache 86400 book_mini_box book.pk %}
- {% include 'catalogue/book_mini_box.html' %}
- {% endcache %}
+ {{ book.mini_box }}
{% endfor %}
{% if theme_fragment %}
{% cache 3600 fragment_promo theme_fragment.pk %}
<section>
<h1>{% trans "Recent publications" %}</h1>
{% for book in last_published %}
- {% cache 86400 book_mini_box book.pk %}
- {% include 'catalogue/book_mini_box.html' %}
- {% endcache %}
+ {{ book.mini_box }}
{% endfor %}
<a class="more" href="{% url 'recent_list' %}">{% trans "More recent publications" %}</a>
</section>
+++ /dev/null
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django import template
-from ssify import ssi_variable
-from ssify.utils import ssi_vary_on_cookie
-
-register = template.Library()
-
-
-@ssi_variable(register, patch_response=[ssi_vary_on_cookie])
-def user_username(request):
- return request.user.username
-
-
-@ssi_variable(register, patch_response=[ssi_vary_on_cookie])
-def user_is_staff(request):
- return request.user.is_staff
url(r'^wesprzyj/', include('funding.urls')),
url(r'^ankieta/', include('polls.urls')),
url(r'^biblioteki/', include('libraries.urls')),
- url(r'^chunks/', include('chunks.urls')),
- url(r'^sponsors/', include('sponsors.urls')),
url(r'^newsletter/', include('newsletter.urls')),
url(r'^formularz/', include('contact.urls')),
url(r'^isbn/', include('isbn.urls')),
import pytz
import re
+from django.conf import settings
+from django.core.cache import cache
from django.core.mail import send_mail
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils import timezone
+from django.utils.translation import get_language
from django.conf import settings
+from django.utils.safestring import mark_safe
from django.utils.translation import ugettext
return True
user_agent = user_agent.lower()
return any(bot_bit in user_agent for bot_bit in BOT_BITS)
+
+
+def get_cached_render_key(instance, property_name, language=None):
+ if language is None:
+ language = get_language()
+ return 'cached_render:%s.%s:%s:%s' % (
+ type(instance).__name__,
+ property_name,
+ instance.pk,
+ language
+ )
+
+
+def cached_render(template_name, timeout=24 * 60 * 60):
+ def decorator(method):
+ @wraps(method)
+ def wrapper(self):
+ key = get_cached_render_key(self, method.__name__)
+ content = cache.get(key)
+ if content is None:
+ context = method(self)
+ content = render_to_string(template_name, context)
+ cache.set(key, str(content), timeout=timeout)
+ else:
+ content = mark_safe(content)
+ return content
+ return wrapper
+ return decorator
+
+
+def clear_cached_renders(bound_method):
+ for lc, ln in settings.LANGUAGES:
+ cache.delete(
+ get_cached_render_key(
+ bound_method.__self__,
+ bound_method.__name__,
+ lc
+ )
+ )