pictures cache fix
[wolnelektury.git] / apps / catalogue / models.py
index 78e6b0b..9f26ae5 100644 (file)
@@ -7,7 +7,7 @@ from collections import namedtuple
 from django.db import models
 from django.db.models import permalink, Q
 import django.dispatch
-from django.core.cache import cache
+from django.core.cache import get_cache
 from django.core.files.storage import DefaultStorage
 from django.utils.translation import ugettext_lazy as _
 from django.contrib.auth.models import User
@@ -17,6 +17,7 @@ from django.utils.safestring import mark_safe
 from django.utils.translation import get_language
 from django.core.urlresolvers import reverse
 from django.db.models.signals import post_save, m2m_changed, pre_delete
+import jsonfield
 
 from django.conf import settings
 
@@ -30,9 +31,9 @@ from glob import glob
 import re
 from os import path
 
-
 import search
 
+# Those are hard-coded here so that makemessages sees them.
 TAG_CATEGORIES = (
     ('author', _('author')),
     ('epoch', _('epoch')),
@@ -43,8 +44,8 @@ TAG_CATEGORIES = (
     ('book', _('book')),
 )
 
-# not quite, but Django wants you to set a timeout
-CACHE_FOREVER = 2419200  # 28 days
+
+permanent_cache = get_cache('permanent')
 
 
 class TagSubcategoryManager(models.Manager):
@@ -371,6 +372,9 @@ class Book(models.Model):
     formats = ebook_formats + ['html', 'xml']
 
     parent        = models.ForeignKey('self', blank=True, null=True, related_name='children')
+
+    _related_info = jsonfield.JSONField(blank=True, null=True, editable=False)
+
     objects  = models.Manager()
     tagged   = managers.ModelTaggedItemManager(Tag)
     tags     = managers.TagDescriptor(Tag)
@@ -449,58 +453,11 @@ class Book(models.Model):
         if self.id is None:
             return
 
-        cache_key = "Book.short_html/%d/%s"
-        for lang, langname in settings.LANGUAGES:
-            cache.delete(cache_key % (self.id, lang))
-        cache.delete("Book.mini_box/%d" % (self.id, ))
+        type(self).objects.filter(pk=self.pk).update(_related_info=None)
         # Fragment.short_html relies on book's tags, so reset it here too
         for fragm in self.fragments.all():
             fragm.reset_short_html()
 
-    def short_html(self):
-        if self.id:
-            cache_key = "Book.short_html/%d/%s" % (self.id, get_language())
-            short_html = cache.get(cache_key)
-        else:
-            short_html = None
-
-        if short_html is not None:
-            return mark_safe(short_html)
-        else:
-            tags = self.tags.filter(category__in=('author', 'kind', 'genre', 'epoch'))
-            tags = split_tags(tags)
-
-            formats = {}
-            # files generated during publication
-            for ebook_format in self.ebook_formats:
-                if self.has_media(ebook_format):
-                    formats[ebook_format] = self.get_media(ebook_format)
-
-
-            short_html = unicode(render_to_string('catalogue/book_short.html',
-                {'book': self, 'tags': tags, 'formats': formats}))
-
-            if self.id:
-                cache.set(cache_key, short_html, CACHE_FOREVER)
-            return mark_safe(short_html)
-
-    def mini_box(self):
-        if self.id:
-            cache_key = "Book.mini_box/%d" % (self.id, )
-            short_html = cache.get(cache_key)
-        else:
-            short_html = None
-
-        if short_html is None:
-            authors = self.tags.filter(category='author')
-
-            short_html = unicode(render_to_string('catalogue/book_mini_box.html',
-                {'book': self, 'authors': authors, 'STATIC_URL': settings.STATIC_URL}))
-
-            if self.id:
-                cache.set(cache_key, short_html, CACHE_FOREVER)
-        return mark_safe(short_html)
-
     def has_description(self):
         return len(self.description) > 0
     has_description.short_description = _('description')
@@ -653,8 +610,9 @@ class Book(models.Model):
 
                 text = fragment.to_string()
                 short_text = ''
-                if (len(MarkupString(text)) > 240):
-                    short_text = unicode(MarkupString(text)[:160])
+                markup = MarkupString(text)
+                if (len(markup) > 240):
+                    short_text = unicode(markup[:160])
                 new_fragment = Fragment.objects.create(anchor=fragment.id, book=self,
                     text=text, short_text=short_text)
 
@@ -687,8 +645,8 @@ class Book(models.Model):
         result = create_zip.delay(paths, "%s_%s" % (self.slug, format_))
         return result.wait()
 
-    def search_index(self, book_info=None):
-        if settings.CELERY_ALWAYS_EAGER:
+    def search_index(self, book_info=None, reuse_index=False):
+        if reuse_index:
             idx = search.ReusableIndex()
         else:
             idx = search.Index()
@@ -791,7 +749,8 @@ class Book(models.Model):
             book.build_mobi()
 
         if not settings.NO_SEARCH_INDEX and search_index:
-            index_book.delay(book.id, book_info)
+            book.search_index()
+            #index_book.delay(book.id, book_info)
 
         book_descendants = list(book.children.all())
         descendants_tags = set()
@@ -817,12 +776,30 @@ class Book(models.Model):
         cls.published.send(sender=book)
         return book
 
+    def related_info(self):
+        """Keeps info about related objects (tags, media) in cache field."""
+        if self._related_info is not None:
+            return self._related_info
+        else:
+            rel = {'tags': {}, 'media': {}}
+            tags = self.tags.filter(category__in=(
+                    'author', 'kind', 'genre', 'epoch'))
+            tags = split_tags(tags)
+            for category in tags:
+                rel['tags'][category] = [
+                        (t.name, t.get_absolute_url()) for t in tags[category]]
+            for media_format in BookMedia.formats:
+                rel['media'][media_format] = self.has_media(media_format)
+            if self.pk:
+                type(self).objects.filter(pk=self.pk).update(_related_info=rel)
+            return rel
+
     def reset_tag_counter(self):
         if self.id is None:
             return
 
         cache_key = "Book.tag_counter/%d" % self.id
-        cache.delete(cache_key)
+        permanent_cache.delete(cache_key)
         if self.parent:
             self.parent.reset_tag_counter()
 
@@ -830,7 +807,7 @@ class Book(models.Model):
     def tag_counter(self):
         if self.id:
             cache_key = "Book.tag_counter/%d" % self.id
-            tags = cache.get(cache_key)
+            tags = permanent_cache.get(cache_key)
         else:
             tags = None
 
@@ -843,7 +820,7 @@ class Book(models.Model):
                 tags[tag.pk] = 1
 
             if self.id:
-                cache.set(cache_key, tags, CACHE_FOREVER)
+                permanent_cache.set(cache_key, tags)
         return tags
 
     def reset_theme_counter(self):
@@ -851,7 +828,7 @@ class Book(models.Model):
             return
 
         cache_key = "Book.theme_counter/%d" % self.id
-        cache.delete(cache_key)
+        permanent_cache.delete(cache_key)
         if self.parent:
             self.parent.reset_theme_counter()
 
@@ -859,7 +836,7 @@ class Book(models.Model):
     def theme_counter(self):
         if self.id:
             cache_key = "Book.theme_counter/%d" % self.id
-            tags = cache.get(cache_key)
+            tags = permanent_cache.get(cache_key)
         else:
             tags = None
 
@@ -870,7 +847,7 @@ class Book(models.Model):
                     tags[tag.pk] = tags.get(tag.pk, 0) + 1
 
             if self.id:
-                cache.set(cache_key, tags, CACHE_FOREVER)
+                permanent_cache.set(cache_key, tags)
         return tags
 
     def pretty_title(self, html_links=False):
@@ -959,6 +936,16 @@ class Book(models.Model):
         audiences = sorted(set([self._audiences_pl[a] for a in audiences]))
         return [a[1] for a in audiences]
 
+    def choose_fragment(self):
+        tag = self.book_tag()
+        fragments = Fragment.tagged.with_any([tag])
+        if fragments.exists():
+            return fragments.order_by('?')[0]
+        elif self.parent:
+            return self.parent.choose_fragment()
+        else:
+            return None
+
 
 def _has_factory(ftype):
     has = lambda self: bool(getattr(self, "%s_file" % ftype))
@@ -1002,12 +989,12 @@ class Fragment(models.Model):
 
         cache_key = "Fragment.short_html/%d/%s"
         for lang, langname in settings.LANGUAGES:
-            cache.delete(cache_key % (self.id, lang))
+            permanent_cache.delete(cache_key % (self.id, lang))
 
     def short_html(self):
         if self.id:
             cache_key = "Fragment.short_html/%d/%s" % (self.id, get_language())
-            short_html = cache.get(cache_key)
+            short_html = permanent_cache.get(cache_key)
         else:
             short_html = None
 
@@ -1017,10 +1004,28 @@ class Fragment(models.Model):
             short_html = unicode(render_to_string('catalogue/fragment_short.html',
                 {'fragment': self}))
             if self.id:
-                cache.set(cache_key, short_html, CACHE_FOREVER)
+                permanent_cache.set(cache_key, short_html)
             return mark_safe(short_html)
 
 
+class Collection(models.Model):
+    """A collection of books, which might be defined before publishing them."""
+    title = models.CharField(_('title'), max_length=120, db_index=True)
+    slug = models.SlugField(_('slug'), max_length=120, primary_key=True)
+    description = models.TextField(_('description'), null=True, blank=True)
+
+    models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
+    book_slugs = models.TextField(_('book slugs'))
+
+    class Meta:
+        ordering = ('title',)
+        verbose_name = _('collection')
+        verbose_name_plural = _('collections')
+
+    def __unicode__(self):
+        return self.title
+
+
 ###########
 #
 # SIGNALS