+ def get_absolute_url(self):
+ return '%s#m%s' % (reverse('book_text', kwargs={'slug': self.book.slug}), self.anchor)
+
+ def short_html(self):
+ key = '_short_html_%s' % get_language()
+ short_html = getattr(self, key)
+ if short_html and len(short_html):
+ return mark_safe(short_html)
+ else:
+ setattr(self, key, unicode(render_to_string('catalogue/fragment_short.html',
+ {'fragment': self})))
+ self.save()
+ return mark_safe(getattr(self, key))
+
+
+class FileRecord(models.Model):
+ slug = models.SlugField(_('slug'), max_length=120, db_index=True)
+ type = models.CharField(_('type'), max_length=20, db_index=True)
+ sha1 = models.CharField(_('sha-1 hash'), max_length=40)
+ time = models.DateTimeField(_('time'), auto_now_add=True)
+
+ class Meta:
+ ordering = ('-time','-slug', '-type')
+ verbose_name = _('file record')
+ verbose_name_plural = _('file records')
+
+ def __unicode__(self):
+ return "%s %s.%s" % (self.sha1, self.slug, self.type)
+
+###########
+#
+# SIGNALS
+#
+###########
+
+
+def _tags_updated_handler(sender, affected_tags, **kwargs):
+ # reset tag global counter
+ Tag.objects.filter(pk__in=[tag.pk for tag in affected_tags]).update(book_count=None)
+
+ # if book tags changed, reset book tag counter
+ if isinstance(sender, Book) and \
+ Tag.objects.filter(pk__in=(tag.pk for tag in affected_tags)).\
+ exclude(category__in=('book', 'theme', 'set')).count():
+ sender.reset_tag_counter()
+ # if fragment theme changed, reset book theme counter
+ elif isinstance(sender, Fragment) and \
+ Tag.objects.filter(pk__in=(tag.pk for tag in affected_tags)).\
+ filter(category='theme').count():
+ sender.book.reset_theme_counter()
+tags_updated.connect(_tags_updated_handler)
+
+
+def _m2m_changed_handler(sender, instance, action, reverse, pk_set, **kwargs):
+ """ refresh all the short_html stuff on BookMedia delete """
+ if sender == Book.medias.through and reverse and action == 'pre_clear':
+ for book in instance.book_set.all():
+ book.save()
+m2m_changed.connect(_m2m_changed_handler)
+
+def _pre_delete_handler(sender, instance, **kwargs):
+ """ explicitly clear m2m, so that Books can be refreshed """
+ if sender == BookMedia:
+ instance.book_set.clear()
+pre_delete.connect(_pre_delete_handler)
+
+def _post_save_handler(sender, instance, **kwargs):
+ """ refresh all the short_html stuff on BookMedia update """
+ if sender == BookMedia:
+ for book in instance.book_set.all():
+ book.save()
+post_save.connect(_post_save_handler)
+