Use unmanaged keys instead of some magic.
authorRadek Czajka <rczajka@rczajka.pl>
Mon, 2 Nov 2020 12:47:58 +0000 (13:47 +0100)
committerRadek Czajka <rczajka@rczajka.pl>
Mon, 2 Nov 2020 12:47:58 +0000 (13:47 +0100)
14 files changed:
src/catalogue/models.py
src/catalogue/templates/catalogue/author_detail.html
src/catalogue/templates/catalogue/book_detail.html
src/catalogue/templates/catalogue/catalogue.html
src/catalogue/utils.py [deleted file]
src/catalogue/views.py
src/documents/ebook_utils.py
src/documents/management/commands/add_parent.py
src/documents/management/commands/insert_isbn.py
src/documents/migrations/0003_auto_20201102_1324.py [new file with mode: 0644]
src/documents/migrations/0004_auto_20201102_1325.py [new file with mode: 0644]
src/documents/migrations/0005_auto_20201102_1340.py [new file with mode: 0644]
src/documents/models/book.py
src/documents/views.py

index cd64f84..1897846 100644 (file)
@@ -6,7 +6,6 @@ from django.urls import reverse
 from django.utils.translation import gettext_lazy as _
 from wikidata.client import Client
 from .constants import WIKIDATA
 from django.utils.translation import gettext_lazy as _
 from wikidata.client import Client
 from .constants import WIKIDATA
-from .utils import UnrelatedManager
 from .wikidata import WikidataMixin
 
 
 from .wikidata import WikidataMixin
 
 
@@ -136,8 +135,6 @@ class Book(WikidataMixin, models.Model):
     estimated_verses = models.IntegerField(_("estimated number of verses"), null=True, blank=True)
     estimate_source = models.CharField(_("source of estimates"), max_length=2048, blank=True)
 
     estimated_verses = models.IntegerField(_("estimated number of verses"), null=True, blank=True)
     estimate_source = models.CharField(_("source of estimates"), max_length=2048, blank=True)
 
-    objects = UnrelatedManager()
-
     class Meta:
         ordering = ("title",)
         verbose_name = _('book')
     class Meta:
         ordering = ("title",)
         verbose_name = _('book')
@@ -170,10 +167,6 @@ class Book(WikidataMixin, models.Model):
     def translators_str(self):
         return ", ".join(str(author) for author in self.translators.all())
 
     def translators_str(self):
         return ", ".join(str(author) for author in self.translators.all())
 
-    def get_document_books(self):
-        DBook = apps.get_model("documents", "Book")
-        return DBook.objects.filter(dc_slug=self.slug)
-
     def get_estimated_costs(self):
         return {
             work_type: work_type.calculate(self)
     def get_estimated_costs(self):
         return {
             work_type: work_type.calculate(self)
index 177f3be..9ee44c3 100644 (file)
@@ -49,7 +49,7 @@
                 {{ book.get_priorty_display }}
               </td>
               <td>
                 {{ book.get_priorty_display }}
               </td>
               <td>
-                {% for b in book.document_books %}
+                {% for b in book.document_books.all %}
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
@@ -75,7 +75,7 @@
                 {{ book.get_priorty_display }}
               </td>
               <td>
                 {{ book.get_priorty_display }}
               </td>
               <td>
-                {% for b in book.document_books %}
+                {% for b in book.document_books.all %}
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
index 2c59c35..85cfcc9 100644 (file)
@@ -67,7 +67,7 @@
             {{ book.get_priorty_display }}
           </td>
           <td>
             {{ book.get_priorty_display }}
           </td>
           <td>
-            {% for b in book.get_document_books %}
+            {% for b in book.document_books.all %}
               <a href="{{ b.get_absolute_url }}">
                 {{ b }}
               </a>
               <a href="{{ b.get_absolute_url }}">
                 {{ b }}
               </a>
index 715ba8f..dca509e 100644 (file)
@@ -50,7 +50,7 @@
                 {{ book.get_priorty_display }}
               </td>
               <td>
                 {{ book.get_priorty_display }}
               </td>
               <td>
-                {% for b in book.document_books %}
+                {% for b in book.document_books.all %}
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
@@ -76,7 +76,7 @@
                 {{ book.get_priorty_display }}
               </td>
               <td>
                 {{ book.get_priorty_display }}
               </td>
               <td>
-                {% for b in book.document_books %}
+                {% for b in book.document_books.all %}
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
                   <a href="{{ b.get_absolute_url }}">
                     {{ b }}
                   </a>
diff --git a/src/catalogue/utils.py b/src/catalogue/utils.py
deleted file mode 100644 (file)
index 00f7187..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from collections import defaultdict
-from django.db.models import QuerySet
-from django.db.models.manager import BaseManager
-
-
-class UnrelatedQuerySet(QuerySet):
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self._prefetch_unrelated_lookups = {}
-        self._prefetch_unrelated_done = False
-
-    def _clone(self):
-        c = super()._clone()
-        c._prefetch_unrelated_lookups = self._prefetch_unrelated_lookups.copy()
-        return c
-
-    def prefetch_unrelated(self, attribute, field, other_model, other_field):
-        clone = self._clone()
-        clone._prefetch_unrelated_lookups[field] = (attribute, other_model, other_field)
-        return clone
-
-    def _fetch_all(self):
-        prefetch_done = self._prefetch_done
-        super()._fetch_all()
-        if self._prefetch_unrelated_lookups and not prefetch_done:
-            self._prefetch_unrelated_objects()
-
-    def _prefetch_unrelated_objects(self):
-        for (
-            field,
-            (attribute, other_model, other_field),
-        ) in self._prefetch_unrelated_lookups.items():
-            values = set([getattr(obj, field) for obj in self._result_cache])
-            other_objects = other_model._default_manager.filter(
-                **{f"{other_field}__in": values}
-            )
-            results = defaultdict(list)
-            for other_obj in other_objects:
-                results[getattr(other_obj, other_field)].append(other_obj)
-            for obj in self._result_cache:
-                setattr(obj, attribute, results.get(getattr(obj, field)))
-        self._prefetch_unrelated_done = True
-
-
-class UnrelatedManager(BaseManager.from_queryset(UnrelatedQuerySet)):
-    pass
index 0b29b6f..792ea70 100644 (file)
@@ -12,13 +12,8 @@ class CatalogueView(TemplateView):
 
     def get_context_data(self):
         ctx = super().get_context_data()
 
     def get_context_data(self):
         ctx = super().get_context_data()
-        documents_books_queryset = models.Book.objects.prefetch_unrelated(
-            "document_books", "slug", documents.models.Book, "dc_slug"
-        )
-        ctx["authors"] = models.Author.objects.all().prefetch_related(
-            Prefetch("book_set", queryset=documents_books_queryset),
-            Prefetch("translated_book_set", queryset=documents_books_queryset),
-        )
+        ctx["authors"] = models.Author.objects.all().prefetch_related('book_set__book_set', 'translated_book_set__book_set')
+
         return ctx
 
 
         return ctx
 
 
@@ -28,12 +23,9 @@ class AuthorView(TemplateView):
 
     def get_context_data(self, slug):
         ctx = super().get_context_data()
 
     def get_context_data(self, slug):
         ctx = super().get_context_data()
-        documents_books_queryset = models.Book.objects.prefetch_unrelated(
-            "document_books", "slug", documents.models.Book, "dc_slug"
-        )
         authors = models.Author.objects.filter(slug=slug).prefetch_related(
         authors = models.Author.objects.filter(slug=slug).prefetch_related(
-            Prefetch("book_set", queryset=documents_books_queryset),
-            Prefetch("translated_book_set", queryset=documents_books_queryset),
+            Prefetch("book_set"),
+            Prefetch("translated_book_set"),
         )
         ctx["author"] = authors.first()
         return ctx
         )
         ctx["author"] = authors.first()
         return ctx
index e75ed77..9253d59 100644 (file)
@@ -14,7 +14,7 @@ class RedakcjaDocProvider(DocProvider):
         self.publishable = publishable
 
     def by_slug(self, slug):
         self.publishable = publishable
 
     def by_slug(self, slug):
-        return BytesIO(Book.objects.get(dc_slug=slug
+        return BytesIO(Book.objects.get(catalogue_book_id=slug
                     ).materialize(publishable=self.publishable
                     ).encode('utf-8'))
 
                     ).materialize(publishable=self.publishable
                     ).encode('utf-8'))
 
index 59767bf..4bd242d 100644 (file)
@@ -71,7 +71,7 @@ class Command(BaseCommand):
 
     def handle(self, slug, **options):
         children_slugs = [line.strip() for line in sys.stdin]
 
     def handle(self, slug, **options):
         children_slugs = [line.strip() for line in sys.stdin]
-        children = Book.objects.filter(dc_slug__in=children_slugs)
+        children = Book.objects.filter(catalogue_book_id__in=children_slugs)
         desc_elements = [dc_desc_element(child) for child in children]
         title = u'Utwory wybrane'
         own_attributes = {
         desc_elements = [dc_desc_element(child) for child in children]
         title = u'Utwory wybrane'
         own_attributes = {
index 536d30f..15104d7 100644 (file)
@@ -62,7 +62,7 @@ class Command(BaseCommand):
 
         for slug, isbn_list in isbn_lists.iteritems():
             print('processing %s' % slug)
 
         for slug, isbn_list in isbn_lists.iteritems():
             print('processing %s' % slug)
-            book = Book.objects.get(dc_slug=slug)
+            book = Book.objects.get(catalogue_book_id=slug)
             chunk = book.chunk_set.first()
             old_head = chunk.head
             src = old_head.materialize()
             chunk = book.chunk_set.first()
             old_head = chunk.head
             src = old_head.materialize()
diff --git a/src/documents/migrations/0003_auto_20201102_1324.py b/src/documents/migrations/0003_auto_20201102_1324.py
new file mode 100644 (file)
index 0000000..79c3073
--- /dev/null
@@ -0,0 +1,20 @@
+# Generated by Django 3.0.4 on 2020-11-02 13:24
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('catalogue', '0029_auto_20201102_1315'),
+        ('documents', '0002_auto_20200322_2131'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='book',
+            name='dc_slug',
+            field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='catalogue.Book', to_field='slug'),
+        ),
+    ]
diff --git a/src/documents/migrations/0004_auto_20201102_1325.py b/src/documents/migrations/0004_auto_20201102_1325.py
new file mode 100644 (file)
index 0000000..2a4eef1
--- /dev/null
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.4 on 2020-11-02 13:25
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('documents', '0003_auto_20201102_1324'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='book',
+            old_name='dc_slug',
+            new_name='catalogue_book',
+        ),
+    ]
diff --git a/src/documents/migrations/0005_auto_20201102_1340.py b/src/documents/migrations/0005_auto_20201102_1340.py
new file mode 100644 (file)
index 0000000..0731fa8
--- /dev/null
@@ -0,0 +1,20 @@
+# Generated by Django 3.0.4 on 2020-11-02 13:40
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('catalogue', '0029_auto_20201102_1315'),
+        ('documents', '0004_auto_20201102_1325'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='book',
+            name='catalogue_book',
+            field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='document_books', related_query_name='document_book', to='catalogue.Book', to_field='slug'),
+        ),
+    ]
index 24d0cea..e16de68 100644 (file)
@@ -30,7 +30,6 @@ class Book(models.Model):
     gallery = models.CharField(_('scan gallery name'), max_length=255, blank=True)
     project = models.ForeignKey(Project, models.SET_NULL, null=True, blank=True)
 
     gallery = models.CharField(_('scan gallery name'), max_length=255, blank=True)
     project = models.ForeignKey(Project, models.SET_NULL, null=True, blank=True)
 
-    #wl_slug = models.CharField(_('title'), max_length=255, null=True, db_index=True, editable=False)
     parent = models.ForeignKey('self', models.SET_NULL, null=True, blank=True, verbose_name=_('parent'), related_name="children", editable=False)
     parent_number = models.IntegerField(_('parent number'), null=True, blank=True, db_index=True, editable=False)
 
     parent = models.ForeignKey('self', models.SET_NULL, null=True, blank=True, verbose_name=_('parent'), related_name="children", editable=False)
     parent_number = models.IntegerField(_('parent number'), null=True, blank=True, db_index=True, editable=False)
 
@@ -41,8 +40,15 @@ class Book(models.Model):
     _on_track = models.IntegerField(null=True, blank=True, db_index=True, editable=False)
     dc_cover_image = models.ForeignKey(Image, blank=True, null=True,
         db_index=True, on_delete=models.SET_NULL, editable=False)
     _on_track = models.IntegerField(null=True, blank=True, db_index=True, editable=False)
     dc_cover_image = models.ForeignKey(Image, blank=True, null=True,
         db_index=True, on_delete=models.SET_NULL, editable=False)
-    dc_slug = models.CharField(max_length=128, null=True, blank=True,
-            editable=False, db_index=True)
+    catalogue_book = models.ForeignKey(
+        'catalogue.Book',
+        models.DO_NOTHING,
+        to_field='slug',
+        null=True, blank=True,
+        editable=False, db_index=True,
+        related_name='document_books',
+        related_query_name='document_book',
+    )
 
     class NoTextError(BaseException):
         pass
 
     class NoTextError(BaseException):
         pass
@@ -90,11 +96,6 @@ class Book(models.Model):
     def gallery_url(self):
         return '%s%s%s/' % (settings.MEDIA_URL, settings.IMAGE_DIR, self.gallery)
 
     def gallery_url(self):
         return '%s%s%s/' % (settings.MEDIA_URL, settings.IMAGE_DIR, self.gallery)
 
-    @property
-    def catalogue_book(self):
-        CBook = apps.get_model('catalogue', 'Book')
-        return CBook.objects.filter(slug=self.dc_slug).first()
-
     # Creating & manipulating
     # =======================
 
     # Creating & manipulating
     # =======================
 
@@ -343,13 +344,15 @@ class Book(models.Model):
 
     def refresh_dc_cache(self):
         update = {
 
     def refresh_dc_cache(self):
         update = {
-            'dc_slug': None,
+            'catalogue_book_id': None,
             'dc_cover_image': None,
         }
 
         info = self.book_info()
             'dc_cover_image': None,
         }
 
         info = self.book_info()
+        print(info)
         if info is not None:
         if info is not None:
-            update['dc_slug'] = info.url.slug
+            update['catalogue_book_id'] = info.url.slug
+            print(info.url.slug)
             if info.cover_source:
                 try:
                     image = Image.objects.get(pk=int(info.cover_source.rstrip('/').rsplit('/', 1)[-1]))
             if info.cover_source:
                 try:
                     image = Image.objects.get(pk=int(info.cover_source.rstrip('/').rsplit('/', 1)[-1]))
@@ -358,6 +361,7 @@ class Book(models.Model):
                 else:
                     if info.cover_source == image.get_full_url():
                         update['dc_cover_image'] = image
                 else:
                     if info.cover_source == image.get_full_url():
                         update['dc_cover_image'] = image
+        print(update)
         Book.objects.filter(pk=self.pk).update(**update)
 
     def touch(self):
         Book.objects.filter(pk=self.pk).update(**update)
 
     def touch(self):
index 397d78b..05f8853 100644 (file)
@@ -224,7 +224,7 @@ def book_xml(request, slug):
 
 @never_cache
 def book_xml_dc(request, slug):
 
 @never_cache
 def book_xml_dc(request, slug):
-    book = get_object_or_404(Book, dc_slug=slug)
+    book = get_object_or_404(Book, catalogue_book_id=slug)
     return serve_xml(request, book, slug)
 
 
     return serve_xml(request, book, slug)