license_name_field = 'document_book__dc_cover_image__license_name'
+class ChildrenFilter(admin.SimpleListFilter):
+ title = 'Status utworu podrzędnego'
+ parameter_name = 'book_children'
+
+ def lookups(self, requesrt, model_admin):
+ return [
+ ('no', 'bez podrzędnych'),
+ ('only', 'tylko podrzędne'),
+ ]
+
+ def queryset(self, request, queryset):
+ v = self.value()
+ if v == 'no':
+ return queryset.filter(parent=None)
+ elif v == 'only':
+ return queryset.exclude(parent=None)
+ else:
+ return queryset
+
+
def add_title(base_class, suffix):
class TitledCategoryFilter(base_class):
def __init__(self, *args, **kwargs):
extra = 1
+class SourcesInline(admin.TabularInline):
+ model = models.EditorNote
+ extra = 1
+
+
class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin, VersionAdmin):
inlines = [SourcesInline]
list_display = [
"translators__first_name", "translators__last_name",
"scans_source", "text_source", "notes", "estimate_source",
]
- autocomplete_fields = ["authors", "translators", "based_on", "epochs", "genres", "kinds"]
+ autocomplete_fields = ["parent", "authors", "translators", "based_on", "epochs", "genres", "kinds"]
filter_horizontal = ['collections']
prepopulated_fields = {"slug": ("title",)}
list_filter = [
+ ChildrenFilter,
"language",
"based_on__language",
("pd_year", RangeNumericFilter),
{
"fields": [
"title",
+ ("parent", "parent_number"),
("slug", 'documents_book_link'),
"authors",
"translators",
'plural',
'is_epoch_specific',
'has_description',
+ 'thema',
+ ]
+ fields = [
+ 'wikidata',
+ 'name',
+ 'plural',
+ 'slug',
+ 'is_epoch_specific',
+ 'thema',
+ 'description',
]
--- /dev/null
+# Generated by Django 4.1.9 on 2024-08-29 13:52
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("catalogue", "0053_alter_thema_code"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="book",
+ name="cover",
+ field=models.FileField(blank=True, upload_to="catalogue/cover"),
+ ),
+ ]
--- /dev/null
+# Generated by Django 4.1.9 on 2024-10-15 13:53
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ("catalogue", "0054_book_cover"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="book",
+ name="parent",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to="catalogue.book",
+ ),
+ ),
+ migrations.AddField(
+ model_name="book",
+ name="parent_number",
+ field=models.IntegerField(blank=True, null=True),
+ ),
+ migrations.CreateModel(
+ name="EditorNote",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ ("changed_at", models.DateTimeField(auto_now=True)),
+ ("note", models.TextField(blank=True)),
+ (
+ "rate",
+ models.IntegerField(
+ choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)], default=3
+ ),
+ ),
+ (
+ "book",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, to="catalogue.book"
+ ),
+ ),
+ (
+ "user",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ ),
+ ]
from collections import Counter
from datetime import date, timedelta
import decimal
+import io
import re
from urllib.request import urlopen
from django.apps import apps
from django.utils.translation import gettext_lazy as _
from admin_ordering.models import OrderableModel
from wikidata.client import Client
+from librarian import DCNS
+from librarian.cover import make_cover
+from librarian.dcparser import BookInfo, Person
from .constants import WIKIDATA
from .wikidata import WikidataModel
from .wikimedia import WikiMedia
class Book(WikidataModel):
slug = models.SlugField(max_length=255, blank=True, null=True, unique=True)
+ parent = models.ForeignKey('self', models.SET_NULL, null=True, blank=True)
+ parent_number = models.IntegerField(null=True, blank=True)
authors = models.ManyToManyField(Author, blank=True, verbose_name=_("authors"))
translators = models.ManyToManyField(
Author,
free_license = models.BooleanField(_('free license'), default=False)
polona_missing = models.BooleanField(_('missing on Polona'), default=False)
+ cover = models.FileField(blank=True, upload_to='catalogue/cover')
+
monthly_views_reader = models.IntegerField(default=0)
monthly_views_page = models.IntegerField(default=0)
txt = f"{txt}, tłum. {tstr}"
return txt
+ def build_cover(self):
+ width, height = 212, 300
+ # TODO: BookInfo shouldn't be required to build a cover.
+ info = BookInfo(rdf_attrs={}, dc_fields={
+ DCNS('creator'): [Person('Mickiewicz', 'Adam')],
+ DCNS('title'): ['Ziutek'],
+ DCNS('date'): ['1900-01-01'],
+ DCNS('publisher'): ['F'],
+ DCNS('language'): ['pol'],
+ DCNS('identifier.url'): ['test'],
+ DCNS('rights'): ['-'],
+ })
+ cover = make_cover(info, width=width, height=height)
+ out = io.BytesIO()
+ ext = cover.ext()
+ cover.save(out)
+ self.cover.save(f'{self.slug}.{ext}', out, save=False)
+ type(self).objects.filter(pk=self.pk).update(cover=self.cover)
+
def get_absolute_url(self):
return reverse("catalogue_book", args=[self.slug])
chars_out_verse = lambda self: self.content_stats.get('chars_out_verse', '')
chars_out_verse_with_fn = lambda self: self.content_stats.get('chars_out_verse_with_fn', '')
+
+class EditorNote(models.Model):
+ book = models.ForeignKey(Book, models.CASCADE)
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
+ created_at = models.DateTimeField(auto_now_add=True)
+ changed_at = models.DateTimeField(auto_now=True)
+ note = models.TextField(blank=True)
+ rate = models.IntegerField(default=3, choices=[
+ (n, n) for n in range(1, 6)
+ ])
+
+
class CollectionCategory(models.Model):
name = models.CharField(_("name"), max_length=255)
parent = models.ForeignKey('self', models.SET_NULL, related_name='children', null=True, blank=True, verbose_name=_("parent"))