Don't cache whole pages, cache what's taking time.
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 26 Apr 2013 14:29:33 +0000 (16:29 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 26 Apr 2013 14:29:33 +0000 (16:29 +0200)
Need to rebuild HTML files after deploying this one.

14 files changed:
apps/catalogue/models/bookmedia.py
apps/catalogue/models/listeners.py
apps/catalogue/templates/catalogue/book_text.html
apps/catalogue/templates/catalogue/catalogue.html
apps/catalogue/views.py
apps/dictionary/views.py
apps/oai/views.py
apps/social/views.py
apps/wolnelektury_core/static/js/dialogs.js
apps/wolnelektury_core/views.py
lib/librarian
lib/sortify.py [changed mode: 0755->0644]
wolnelektury/settings/__init__.py
wolnelektury/settings/cache.py

index bf05e21..fb5d588 100644 (file)
@@ -2,6 +2,7 @@
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
+import json
 from collections import namedtuple
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
@@ -60,6 +61,9 @@ class BookMedia(models.Model):
         remove_zip("%s_%s" % (self.book.slug, self.type))
 
         extra_info = self.extra_info
+        if isinstance(extra_info, basestring):
+            # Walkaround for weird jsonfield 'no-decode' optimization.
+            extra_info = json.loads(extra_info)
         extra_info.update(self.read_meta())
         self.extra_info = extra_info
         self.source_sha1 = self.read_source_sha1(self.file.path, self.type)
index 41c974a..cb10616 100644 (file)
@@ -53,6 +53,7 @@ post_save.connect(_post_save_handler)
 
 def post_publish(sender, **kwargs):
     permanent_cache.delete('catalogue.book_list')
+    permanent_cache.delete('catalogue.catalogue')
 Book.published.connect(post_publish)
 
 
index 6addd41..aa2b392 100644 (file)
         <div id="header">
             <a href="/"><img src="{% static "img/logo-220.png" %}" alt="Wolne Lektury" /></a>
         </div>
-        <div id="themes">
-            <ol>
-                {% for theme, fragments in book_themes %}
-                <li>{{ theme }}:
-                    {% for fragment in fragments %}
-                        <a href="#m{{ fragment.anchor }}">{{ forloop.counter }}</a>
-                    {% endfor %}
-                </li>
-                {% endfor %}
-            </ol>
-        </div>
         {{ book.html_file.read|safe }}
         {{ piwik_tag|safe }}
     </body>
index 228a415..c7cee40 100644 (file)
     </a></p>
 
     <h2 class="white-box">{% trans "Authors" %}<a name="autorzy"></a></h2>
-    <div class="white-box">{% tag_list categories.author %}</div>
+    <div class="white-box">{{ output.author }}</div>
 
     <h2 class="white-box">{% trans "Kinds" %}<a name="rodzaje"></a></h2>
-    <div class="white-box" lang="pl">{% tag_list categories.kind %}</div>
+    <div class="white-box" lang="pl">{{ output.kind }}</div>
 
     <h2 class="white-box">{% trans "Genres" %}<a name="gatunki"></a></h2>
-    <div class="white-box" lang="pl">{% tag_list categories.genre %}</div>
+    <div class="white-box" lang="pl">{{ output.genre }}</div>
 
     <h2 class="white-box">{% trans "Epochs" %}<a name="epoki"></a></h2>
-    <div class="white-box" lang="pl">{% tag_list categories.epoch %}</div>
+    <div class="white-box" lang="pl">{{ output.epoch }}</div>
 
     <h2 class="white-box">{% trans "Themes and topics" %}<a name="motywy"></a></h2>
-    <div class="white-box" lang="pl">{% tag_list fragment_tags %}</div>
+    <div class="white-box" lang="pl">{{ output.theme }}</div>
 
     <h2 class="white-box">{% trans "Collections" %}<a name="kolekcje"></a></h2>
-    <div class="white-box" lang="pl">{% collection_list collections %}</div>
+    <div class="white-box" lang="pl">{{ output.collections }}</div>
 
     </div>
 {% endblock %}
index e61feb6..92ecebf 100644 (file)
@@ -18,7 +18,6 @@ from django.utils.datastructures import SortedDict
 from django.utils.http import urlquote_plus
 from django.utils import translation
 from django.utils.translation import ugettext as _, ugettext_lazy
-from django.views.decorators.cache import never_cache
 from django.views.decorators.vary import vary_on_headers
 
 from ajaxable.utils import JSONResponse, AjaxableFormView
@@ -37,16 +36,17 @@ permanent_cache = get_cache('permanent')
 
 @vary_on_headers('X-Requested-With')
 def catalogue(request):
-    tags = models.Tag.objects.exclude(
-        category__in=('set', 'book')).exclude(book_count=0)
-    tags = list(tags)
-    for tag in tags:
-        tag.count = tag.book_count
-    categories = split_tags(tags)
-    fragment_tags = categories.get('theme', [])
-    collections = models.Collection.objects.all()
-
-    if request.is_ajax():
+    cache_key='catalogue.catalogue'
+    output = permanent_cache.get(cache_key)
+    if output is None:
+        tags = models.Tag.objects.exclude(
+            category__in=('set', 'book')).exclude(book_count=0)
+        tags = list(tags)
+        for tag in tags:
+            tag.count = tag.book_count
+        categories = split_tags(tags)
+        fragment_tags = categories.get('theme', [])
+        collections = models.Collection.objects.all()
         render_tag_list = lambda x: render_to_string(
             'catalogue/tag_list.html', tag_list(x))
         output = {'theme': render_tag_list(fragment_tags)}
@@ -54,13 +54,16 @@ def catalogue(request):
             output[category] = render_tag_list(tags)
         output['collections'] = render_to_string(
             'catalogue/collection_list.html', collection_list(collections))
+        permanent_cache.set(cache_key, output)
+    if request.is_ajax():
         return JSONResponse(output)
     else:
         return render_to_response('catalogue/catalogue.html', locals(),
             context_instance=RequestContext(request))
 
 
-def book_list(request, filter=None, template_name='catalogue/book_list.html',
+def book_list(request, filter=None, get_filter=None,
+        template_name='catalogue/book_list.html',
         nav_template_name='catalogue/snippets/book_list_nav.html',
         list_template_name='catalogue/snippets/book_list.html',
         cache_key='catalogue.book_list',
@@ -71,6 +74,8 @@ def book_list(request, filter=None, template_name='catalogue/book_list.html',
     if cached is not None:
         rendered_nav, rendered_book_list = cached
     else:
+        if get_filter:
+            filter = get_filter()
         books_by_author, orphans, books_by_parent = models.Book.book_list(filter)
         books_nav = SortedDict()
         for tag in books_by_author:
@@ -98,11 +103,13 @@ def daisy_list(request):
 
 def collection(request, slug):
     coll = get_object_or_404(models.Collection, slug=slug)
-    slugs = coll.book_slugs.split()
-    # allow URIs
-    slugs = [slug.rstrip('/').rsplit('/', 1)[-1] if '/' in slug else slug
-                for slug in slugs]
-    return book_list(request, Q(slug__in=slugs),
+    def get_filter():
+        slugs = coll.book_slugs.split()
+        # allow URIs
+        slugs = [slug.rstrip('/').rsplit('/', 1)[-1] if '/' in slug else slug
+                    for slug in slugs]
+        return Q(slug__in=slugs)
+    return book_list(request, get_filter=get_filter,
                      template_name='catalogue/collection.html',
                      cache_key='catalogue.collection:%s' % coll.slug,
                      context={'collection': coll})
@@ -122,7 +129,6 @@ def differentiate_tags(request, tags, ambiguous_slugs):
                 context_instance=RequestContext(request))
 
 
-@never_cache
 def tagged_object_list(request, tags=''):
     try:
         tags = models.Tag.get_tag_list(tags)
@@ -231,7 +237,6 @@ def book_fragments(request, slug, theme_slug):
         context_instance=RequestContext(request))
 
 
-@never_cache
 def book_detail(request, slug):
     try:
         book = models.Book.objects.get(slug=slug)
@@ -287,13 +292,6 @@ def book_text(request, slug):
 
     if not book.has_html_file():
         raise Http404
-    book_themes = {}
-    for fragment in book.fragments.all().iterator():
-        for theme in fragment.tags.filter(category='theme').iterator():
-            book_themes.setdefault(theme, []).append(fragment)
-
-    book_themes = book_themes.items()
-    book_themes.sort(key=lambda s: s[0].sort_key)
     related = book.related_info()
     return render_to_response('catalogue/book_text.html', locals(),
         context_instance=RequestContext(request))
index 4208d9b..76c89cd 100755 (executable)
@@ -11,7 +11,7 @@ class NotesView(ListView):
         self.letters = ["0-9"] + [chr(a) for a in range(ord('a'), ord('z')+1)]
         self.letter = self.kwargs.get('letter')
 
-        objects = Note.objects.all()
+        objects = Note.objects.select_related('book').all()
         if self.letter == "0-9":
             objects = objects.filter(sort_key__regex=r"^[0-9]")
         elif self.letter:
index af4bd1c..5ef5bd4 100644 (file)
@@ -44,7 +44,6 @@ def qdc_writer(element, metadata):
 
     for name in ['hasPart', 'isPartOf']:
         for value in map.get(name, []):
-            print "%s %s" % (name, value)
             e = SubElement(element, nsdcterms(name), nsmap=nsmap)
             e.text = value
 
index 27769d7..8af17da 100644 (file)
@@ -61,7 +61,10 @@ class ObjectSetsFormView(AjaxableFormView):
         return (obj, request.user), {}
 
 
+@require_POST
 def unlike_book(request, slug):
+    if not request.user.is_authenticated():
+        return HttpResponseForbidden('Login required.')
     book = get_object_or_404(Book, slug=slug)
     if likes(request.user, book):
         set_sets(request.user, book, [])
index bd412bc..3b7553b 100755 (executable)
         };
 
         var ajaxable_callbacks = {
-            'social-book-sets': location.reload
+            'social-book-sets': function() {location.reload();}
         };
 
 
index f62a142..ae582ce 100644 (file)
@@ -19,7 +19,6 @@ from ajaxable.utils import placeholdized
 from social.templatetags.social_tags import choose_cite
 
 
-@never_cache
 def main_page(request):
     last_published = Book.objects.filter(parent=None).order_by('-created_at')[:4]
     cite = choose_cite(RequestContext(request))
@@ -90,6 +89,7 @@ def logout_then_redirect(request):
     return HttpResponseRedirect(urlquote_plus(request.GET.get('next', '/'), safe='/?='))
 
 
+@never_cache
 def clock(request):
     """ Provides server time for jquery.countdown,
     in a format suitable for Date.parse()
index 3754989..181c573 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3754989331c91f1d78cd5c1904f768a4cf80f07a
+Subproject commit 181c5739f47d2adb00ba115bb4766584a1bc37e4
old mode 100755 (executable)
new mode 100644 (file)
index 8fdb973..1f0d1d2 100644 (file)
@@ -26,7 +26,6 @@ TEMPLATE_CONTEXT_PROCESSORS = (
 )
 
 MIDDLEWARE_CLASSES = [
-    'django.middleware.cache.UpdateCacheMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
@@ -37,7 +36,6 @@ MIDDLEWARE_CLASSES = [
     'piwik.django.middleware.PiwikMiddleware',
     'maintenancemode.middleware.MaintenanceModeMiddleware',
     'django.middleware.common.CommonMiddleware',
-    'django.middleware.cache.FetchFromCacheMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'fnpdjango.middleware.SetRemoteAddrFromXRealIP',
 ]
index 14edd53..3e27b5f 100644 (file)
@@ -22,4 +22,3 @@ CACHES = {
         'TIMEOUT': 86400,
     },
 }
-CACHE_MIDDLEWARE_ANONYMOUS_ONLY=True