optimize db usage in tagged object list
[wolnelektury.git] / src / catalogue / models / book.py
index 676f9c0..5ac999e 100644 (file)
@@ -4,7 +4,9 @@
 #
 from collections import OrderedDict
 from random import randint
 #
 from collections import OrderedDict
 from random import randint
+import os.path
 import re
 import re
+import urllib
 from django.conf import settings
 from django.db import connection, models, transaction
 from django.db.models import permalink
 from django.conf import settings
 from django.db import connection, models, transaction
 from django.db.models import permalink
@@ -19,9 +21,11 @@ from newtagging import managers
 from catalogue import constants
 from catalogue.fields import EbookField
 from catalogue.models import Tag, Fragment, BookMedia
 from catalogue import constants
 from catalogue.fields import EbookField
 from catalogue.models import Tag, Fragment, BookMedia
-from catalogue.utils import create_zip
+from catalogue.utils import create_zip, gallery_url, gallery_path
+from catalogue.models.tag import prefetched_relations
 from catalogue import app_settings
 from catalogue import tasks
 from catalogue import app_settings
 from catalogue import tasks
+from wolnelektury.utils import makedirs
 
 bofh_storage = BofhFileSystemStorage()
 
 
 bofh_storage = BofhFileSystemStorage()
 
@@ -103,8 +107,18 @@ class Book(models.Model):
         except AttributeError:
             return ''
 
         except AttributeError:
             return ''
 
-    def author_str(self):
-        return ", ".join(str(t) for t in self.tags.filter(category='author'))
+    def authors(self):
+        return self.tags.filter(category='author')
+
+    def tag_unicode(self, category):
+        relations = prefetched_relations(self, category)
+        if relations:
+            return ', '.join(rel.tag.name for rel in relations)
+        else:
+            return ', '.join(self.tags.filter(category=category).values_list('name', flat=True))
+
+    def author_unicode(self):
+        return self.tag_unicode('author')
 
     def save(self, force_insert=False, force_update=False, **kwargs):
         from sortify import sortify
 
     def save(self, force_insert=False, force_update=False, **kwargs):
         from sortify import sortify
@@ -113,8 +127,8 @@ class Book(models.Model):
         self.title = unicode(self.title)  # ???
 
         try:
         self.title = unicode(self.title)  # ???
 
         try:
-            author = self.tags.filter(category='author')[0].sort_key
-        except IndexError:
+            author = self.authors().first().sort_key
+        except AttributeError:
             author = u''
         self.sort_key_author = author
 
             author = u''
         self.sort_key_author = author
 
@@ -131,6 +145,12 @@ class Book(models.Model):
     def create_url(slug):
         return 'catalogue.views.book_detail', [slug]
 
     def create_url(slug):
         return 'catalogue.views.book_detail', [slug]
 
+    def gallery_path(self):
+        return gallery_path(self.slug)
+
+    def gallery_url(self):
+        return gallery_url(self.slug)
+
     @property
     def name(self):
         return self.title
     @property
     def name(self):
         return self.title
@@ -141,6 +161,9 @@ class Book(models.Model):
     def language_name(self):
         return dict(settings.LANGUAGES).get(self.language_code(), "")
 
     def language_name(self):
         return dict(settings.LANGUAGES).get(self.language_code(), "")
 
+    def is_foreign(self):
+        return self.language_code() != settings.LANGUAGE_CODE
+
     def has_media(self, type_):
         if type_ in Book.formats:
             return bool(getattr(self, "%s_file" % type_))
     def has_media(self, type_):
         if type_ in Book.formats:
             return bool(getattr(self, "%s_file" % type_))
@@ -236,6 +259,21 @@ class Book(models.Model):
             index.index.rollback()
             raise e
 
             index.index.rollback()
             raise e
 
+    def download_pictures(self, remote_gallery_url):
+        gallery_path = self.gallery_path()
+        # delete previous files, so we don't include old files in ebooks
+        if os.path.isdir(gallery_path):
+            for filename in os.listdir(gallery_path):
+                file_path = os.path.join(gallery_path, filename)
+                os.unlink(file_path)
+        ilustr_elements = list(self.wldocument().edoc.findall('//ilustr'))
+        if ilustr_elements:
+            makedirs(gallery_path)
+            for ilustr in ilustr_elements:
+                ilustr_src = ilustr.get('src')
+                ilustr_path = os.path.join(gallery_path, ilustr_src)
+                urllib.urlretrieve('%s/%s' % (remote_gallery_url, ilustr_src), ilustr_path)
+
     @classmethod
     def from_xml_file(cls, xml_file, **kwargs):
         from django.core.files import File
     @classmethod
     def from_xml_file(cls, xml_file, **kwargs):
         from django.core.files import File
@@ -254,7 +292,7 @@ class Book(models.Model):
 
     @classmethod
     def from_text_and_meta(cls, raw_file, book_info, overwrite=False, dont_build=None, search_index=True,
 
     @classmethod
     def from_text_and_meta(cls, raw_file, book_info, overwrite=False, dont_build=None, search_index=True,
-                           search_index_tags=True):
+                           search_index_tags=True, remote_gallery_url=None):
         if dont_build is None:
             dont_build = set()
         dont_build = set.union(set(dont_build), set(app_settings.DONT_BUILD))
         if dont_build is None:
             dont_build = set()
         dont_build = set.union(set(dont_build), set(app_settings.DONT_BUILD))
@@ -322,6 +360,9 @@ class Book(models.Model):
         cls.repopulate_ancestors()
         tasks.update_counters.delay()
 
         cls.repopulate_ancestors()
         tasks.update_counters.delay()
 
+        if remote_gallery_url:
+            book.download_pictures(remote_gallery_url)
+
         # No saves beyond this point.
 
         # Build cover.
         # No saves beyond this point.
 
         # Build cover.
@@ -448,7 +489,7 @@ class Book(models.Model):
         return books
 
     def pretty_title(self, html_links=False):
         return books
 
     def pretty_title(self, html_links=False):
-        names = [(tag.name, tag.get_absolute_url()) for tag in self.tags.filter(category='author')]
+        names = [(tag.name, tag.get_absolute_url()) for tag in self.authors().only('name', 'category', 'slug')]
         books = self.parents() + [self]
         names.extend([(b.title, b.get_absolute_url()) for b in books])
 
         books = self.parents() + [self]
         names.extend([(b.title, b.get_absolute_url()) for b in books])
 
@@ -478,8 +519,7 @@ class Book(models.Model):
         """
 
         books_by_parent = {}
         """
 
         books_by_parent = {}
-        books = cls.objects.all().order_by('parent_number', 'sort_key').only(
-                'title', 'parent', 'slug')
+        books = cls.objects.order_by('parent_number', 'sort_key').only('title', 'parent', 'slug')
         if book_filter:
             books = books.filter(book_filter).distinct()
 
         if book_filter:
             books = books.filter(book_filter).distinct()
 
@@ -499,7 +539,7 @@ class Book(models.Model):
             books_by_author[tag] = []
 
         for book in books_by_parent.get(None, ()):
             books_by_author[tag] = []
 
         for book in books_by_parent.get(None, ()):
-            authors = list(book.tags.filter(category='author'))
+            authors = list(book.authors().only('pk'))
             if authors:
                 for author in authors:
                     books_by_author[author].append(book)
             if authors:
                 for author in authors:
                     books_by_author[author].append(book)