--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting field 'Book._short_html_en'
+ db.delete_column('catalogue_book', '_short_html_en')
+
+ # Deleting field 'Book._short_html_es'
+ db.delete_column('catalogue_book', '_short_html_es')
+
+ # Deleting field 'Book._theme_counter'
+ db.delete_column('catalogue_book', '_theme_counter')
+
+ # Deleting field 'Book._short_html_de'
+ db.delete_column('catalogue_book', '_short_html_de')
+
+ # Deleting field 'Book._short_html_fr'
+ db.delete_column('catalogue_book', '_short_html_fr')
+
+ # Deleting field 'Book._short_html_uk'
+ db.delete_column('catalogue_book', '_short_html_uk')
+
+ # Deleting field 'Book._short_html_pl'
+ db.delete_column('catalogue_book', '_short_html_pl')
+
+ # Deleting field 'Book._short_html_lt'
+ db.delete_column('catalogue_book', '_short_html_lt')
+
+ # Deleting field 'Book._short_html_ru'
+ db.delete_column('catalogue_book', '_short_html_ru')
+
+ # Deleting field 'Book._short_html'
+ db.delete_column('catalogue_book', '_short_html')
+
+ # Deleting field 'Book._tag_counter'
+ db.delete_column('catalogue_book', '_tag_counter')
+
+ # Deleting field 'Fragment._short_html_de'
+ db.delete_column('catalogue_fragment', '_short_html_de')
+
+ # Deleting field 'Fragment._short_html_en'
+ db.delete_column('catalogue_fragment', '_short_html_en')
+
+ # Deleting field 'Fragment._short_html_fr'
+ db.delete_column('catalogue_fragment', '_short_html_fr')
+
+ # Deleting field 'Fragment._short_html_es'
+ db.delete_column('catalogue_fragment', '_short_html_es')
+
+ # Deleting field 'Fragment._short_html_uk'
+ db.delete_column('catalogue_fragment', '_short_html_uk')
+
+ # Deleting field 'Fragment._short_html_pl'
+ db.delete_column('catalogue_fragment', '_short_html_pl')
+
+ # Deleting field 'Fragment._short_html_lt'
+ db.delete_column('catalogue_fragment', '_short_html_lt')
+
+ # Deleting field 'Fragment._short_html_ru'
+ db.delete_column('catalogue_fragment', '_short_html_ru')
+
+ # Deleting field 'Fragment._short_html'
+ db.delete_column('catalogue_fragment', '_short_html')
+
+
+ def backwards(self, orm):
+
+ # Adding field 'Book._short_html_en'
+ db.add_column('catalogue_book', '_short_html_en', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._short_html_es'
+ db.add_column('catalogue_book', '_short_html_es', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._theme_counter'
+ db.add_column('catalogue_book', '_theme_counter', self.gf('catalogue.fields.JSONField')(null=True), keep_default=False)
+
+ # Adding field 'Book._short_html_de'
+ db.add_column('catalogue_book', '_short_html_de', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._short_html_fr'
+ db.add_column('catalogue_book', '_short_html_fr', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._short_html_uk'
+ db.add_column('catalogue_book', '_short_html_uk', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._short_html_pl'
+ db.add_column('catalogue_book', '_short_html_pl', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._short_html_lt'
+ db.add_column('catalogue_book', '_short_html_lt', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._short_html_ru'
+ db.add_column('catalogue_book', '_short_html_ru', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Book._short_html'
+ db.add_column('catalogue_book', '_short_html', self.gf('django.db.models.fields.TextField')(default=''), keep_default=False)
+
+ # Adding field 'Book._tag_counter'
+ db.add_column('catalogue_book', '_tag_counter', self.gf('catalogue.fields.JSONField')(null=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_de'
+ db.add_column('catalogue_fragment', '_short_html_de', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_en'
+ db.add_column('catalogue_fragment', '_short_html_en', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_fr'
+ db.add_column('catalogue_fragment', '_short_html_fr', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_es'
+ db.add_column('catalogue_fragment', '_short_html_es', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_uk'
+ db.add_column('catalogue_fragment', '_short_html_uk', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_pl'
+ db.add_column('catalogue_fragment', '_short_html_pl', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_lt'
+ db.add_column('catalogue_fragment', '_short_html_lt', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html_ru'
+ db.add_column('catalogue_fragment', '_short_html_ru', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Fragment._short_html'
+ db.add_column('catalogue_fragment', '_short_html', self.gf('django.db.models.fields.TextField')(default=''), keep_default=False)
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.filerecord': {
+ 'Meta': {'ordering': "('-time', '-slug', '-type')", 'object_name': 'FileRecord'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'sha1': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '20', 'db_index': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
from django.db import models
from django.db.models import permalink, Q
+from django.core.cache import cache
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.core.files import File
description = models.TextField(_('description'), blank=True)
created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
- _short_html = models.TextField(_('short HTML'), editable=False)
parent_number = models.IntegerField(_('parent number'), default=0)
extra_info = JSONField(_('extra information'), default='{}')
gazeta_link = models.CharField(blank=True, max_length=240)
tagged = managers.ModelTaggedItemManager(Tag)
tags = managers.TagDescriptor(Tag)
- _tag_counter = JSONField(null=True, editable=False)
- _theme_counter = JSONField(null=True, editable=False)
-
class AlreadyExists(Exception):
pass
self.sort_key = sortify(self.title)
if reset_short_html:
- # Reset _short_html during save
- update = {}
- for key in filter(lambda x: x.startswith('_short_html'), self.__dict__):
- update[key] = ''
- self.__setattr__(key, '')
- # Fragment.short_html relies on book's tags, so reset it here too
- self.fragments.all().update(**update)
+ self.reset_short_html()
return super(Book, self).save(force_insert, force_update)
def get_daisy(self):
return self.get_media("daisy")
+ def reset_short_html(self):
+ cache_key = "Book.short_html/%d/%s"
+ for lang, langname in settings.LANGUAGES:
+ cache.delete(cache_key % (self.id, lang))
+ # 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):
- key = '_short_html_%s' % get_language()
- short_html = getattr(self, key)
+ cache_key = "Book.short_html/%d/%s" % (self.id, get_language())
+ short_html = cache.get(cache_key)
- if short_html and len(short_html):
+ if short_html is not None:
+ print 'b.s from cache'
return mark_safe(short_html)
else:
+ print 'b.s manual'
tags = self.tags.filter(~Q(category__in=('set', 'theme', 'book')))
tags = [mark_safe(u'<a href="%s">%s</a>' % (tag.get_absolute_url(), tag.name)) for tag in tags]
formats = [mark_safe(format) for format in formats]
- setattr(self, key, unicode(render_to_string('catalogue/book_short.html',
- {'book': self, 'tags': tags, 'formats': formats})))
- self.save(reset_short_html=False)
- return mark_safe(getattr(self, key))
-
+ short_html = unicode(render_to_string('catalogue/book_short.html',
+ {'book': self, 'tags': tags, 'formats': formats}))
+ cache.set(cache_key, short_html)
+ return mark_safe(short_html)
@property
def root_ancestor(self):
book.title = book_info.title
book.set_extra_info_value(book_info.to_dict())
- book._short_html = ''
book.save()
meta_tags = []
book.save()
return book
-
- def refresh_tag_counter(self):
- tags = {}
- for child in self.children.all().order_by():
- for tag_pk, value in child.tag_counter.iteritems():
- tags[tag_pk] = tags.get(tag_pk, 0) + value
- for tag in self.tags.exclude(category__in=('book', 'theme', 'set')).order_by():
- tags[tag.pk] = 1
- self.set__tag_counter_value(tags)
- self.save(reset_short_html=False)
- return tags
-
def reset_tag_counter(self):
- self._tag_counter = None
- self.save(reset_short_html=False)
+ cache_key = "Book.tag_counter/%d" % self.id
+ cache.delete(cache_key)
if self.parent:
self.parent.reset_tag_counter()
@property
def tag_counter(self):
- if self._tag_counter is None:
- return self.refresh_tag_counter()
- return dict((int(k), v) for k, v in self.get__tag_counter_value().iteritems())
-
- def refresh_theme_counter(self):
- tags = {}
- for fragment in Fragment.tagged.with_any([self.book_tag()]).order_by():
- for tag in fragment.tags.filter(category='theme').order_by():
- tags[tag.pk] = tags.get(tag.pk, 0) + 1
- self.set__theme_counter_value(tags)
- self.save(reset_short_html=False)
+ cache_key = "Book.tag_counter/%d" % self.id
+ tags = cache.get(cache_key)
+ print 'tag'
+ if tags is None:
+ print 'tag manual'
+ tags = {}
+ for child in self.children.all().order_by():
+ for tag_pk, value in child.tag_counter.iteritems():
+ tags[tag_pk] = tags.get(tag_pk, 0) + value
+ for tag in self.tags.exclude(category__in=('book', 'theme', 'set')).order_by():
+ tags[tag.pk] = 1
+
+ cache.set(cache_key, tags)
return tags
def reset_theme_counter(self):
- self._theme_counter = None
- self.save(reset_short_html=False)
+ cache_key = "Book.theme_counter/%d" % self.id
+ cache.delete(cache_key)
if self.parent:
self.parent.reset_theme_counter()
@property
def theme_counter(self):
- if self._theme_counter is None:
- return self.refresh_theme_counter()
- return dict((int(k), v) for k, v in self.get__theme_counter_value().iteritems())
+ cache_key = "Book.theme_counter/%d" % self.id
+ tags = cache.get(cache_key)
+ print 'theme'
+ if tags is None:
+ print 'theme manual'
+ tags = {}
+ for fragment in Fragment.tagged.with_any([self.book_tag()]).order_by():
+ for tag in fragment.tags.filter(category='theme').order_by():
+ tags[tag.pk] = tags.get(tag.pk, 0) + 1
+
+ cache.set(cache_key, tags)
+ return tags
def pretty_title(self, html_links=False):
book = self
class Fragment(models.Model):
text = models.TextField()
short_text = models.TextField(editable=False)
- _short_html = models.TextField(editable=False)
anchor = models.CharField(max_length=120)
book = models.ForeignKey(Book, related_name='fragments')
def get_absolute_url(self):
return '%s#m%s' % (reverse('book_text', kwargs={'slug': self.book.slug}), self.anchor)
+ def reset_short_html(self):
+ cache_key = "Fragment.short_html/%d/%s"
+ for lang, langname in settings.LANGUAGES:
+ cache.delete(cache_key % (self.id, lang))
+
def short_html(self):
- key = '_short_html_%s' % get_language()
- short_html = getattr(self, key)
- if short_html and len(short_html):
+ cache_key = "Fragment.short_html/%d/%s" % (self.id, get_language())
+ short_html = cache.get(cache_key)
+
+ if short_html is not None:
+ print 'f.s from cache'
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))
+ print 'f.s manual'
+ short_html = unicode(render_to_string('catalogue/fragment_short.html',
+ {'fragment': self}))
+ cache.set(cache_key, short_html)
+ return mark_safe(short_html)
class FileRecord(models.Model):