From: Radek Czajka Date: Thu, 22 Sep 2022 14:03:22 +0000 (+0200) Subject: More data in catalogue X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/8161763bf98b7f396ecc349ccd4670b8de592f40 More data in catalogue --- diff --git a/src/catalogue/admin.py b/src/catalogue/admin.py index 47152ebb..213e9ca7 100644 --- a/src/catalogue/admin.py +++ b/src/catalogue/admin.py @@ -16,7 +16,7 @@ from .wikidata import WikidataAdminMixin class NotableBookInline(OrderableAdmin, admin.TabularInline): model = models.NotableBook - raw_id_fields = ['book'] + autocomplete_fields = ['book'] ordering_field_hide_input = True @@ -45,8 +45,35 @@ class AuthorAdmin(WikidataAdminMixin, TabbedTranslationAdmin): ] list_per_page = 10000000 search_fields = ["first_name", "last_name", "wikidata"] + readonly_fields = ["wikidata_link"] + + fieldsets = [ + (None, {"fields": [("wikidata", "wikidata_link")]}), + ( + _("Identification"), + { + "fields": [ + ("first_name", "last_name"), + "slug", + "gender", + "nationality", + ("date_of_birth", "year_of_birth", "year_of_birth_inexact", "year_of_birth_range", "place_of_birth"), + ("date_of_death", "year_of_death", "year_of_death_inexact", "year_of_death_range", "place_of_death"), + "description", + "status", + "collections", + "priority", + + "notes", + "gazeta_link", + "culturepl_link", + ] + }, + ), + ] + prepopulated_fields = {"slug": ("first_name", "last_name")} - autocomplete_fields = ["collections"] + autocomplete_fields = ["collections", "place_of_birth", "place_of_death"] inlines = [ NotableBookInline, ] @@ -316,3 +343,8 @@ class WorkTypeAdmin(admin.ModelAdmin): admin.site.register(models.WorkType, WorkTypeAdmin) + + +@admin.register(models.Place) +class PlaceAdmin(WikidataAdminMixin, TabbedTranslationAdmin): + search_fields = ['name'] diff --git a/src/catalogue/constants.py b/src/catalogue/constants.py index 9134e2d3..0f961b9d 100644 --- a/src/catalogue/constants.py +++ b/src/catalogue/constants.py @@ -2,10 +2,13 @@ # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # class WIKIDATA: + PLACE_OF_BIRTH = 'P19' + PLACE_OF_DEATH = 'P20' GENDER = "P21" AUTHOR = "P50" CREATOR = "P170" LANGUAGE = "P407" + DATE_OF_BIRTH = "P569" DATE_OF_DEATH = "P570" LAST_NAME = "P734" GIVEN_NAME = "P735" diff --git a/src/catalogue/locale/pl/LC_MESSAGES/django.mo b/src/catalogue/locale/pl/LC_MESSAGES/django.mo index 3dbf04be..39239f88 100644 Binary files a/src/catalogue/locale/pl/LC_MESSAGES/django.mo and b/src/catalogue/locale/pl/LC_MESSAGES/django.mo differ diff --git a/src/catalogue/locale/pl/LC_MESSAGES/django.po b/src/catalogue/locale/pl/LC_MESSAGES/django.po index ad827e5e..044f9605 100644 --- a/src/catalogue/locale/pl/LC_MESSAGES/django.po +++ b/src/catalogue/locale/pl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2022-09-19 15:45+0200\n" +"PO-Revision-Date: 2022-09-22 15:57+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: pl\n" @@ -19,29 +19,27 @@ msgstr "" "n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" "X-Generator: Poedit 3.0.1\n" -#: catalogue/admin.py:176 +#: catalogue/admin.py:53 catalogue/admin.py:203 msgid "Identification" msgstr "Identyfikacja" -#: catalogue/admin.py:190 +#: catalogue/admin.py:217 msgid "Features" msgstr "Cechy" -#: catalogue/admin.py:200 +#: catalogue/admin.py:227 msgid "Plan" msgstr "Plan" -#: catalogue/admin.py:242 -#, fuzzy -#| msgid "title" +#: catalogue/admin.py:269 msgid "Title" msgstr "tytuł" -#: catalogue/admin.py:248 +#: catalogue/admin.py:275 msgid "Book" msgstr "książka" -#: catalogue/admin.py:258 catalogue/models.py:139 +#: catalogue/admin.py:285 catalogue/models.py:160 msgid "scans source" msgstr "źródło skanów" @@ -73,217 +71,253 @@ msgstr "narodowość" msgid "year of birth" msgstr "rok urodzenia" -#: catalogue/models.py:24 +#: catalogue/models.py:24 catalogue/models.py:33 +msgid "inexact" +msgstr "niedokładny" + +#: catalogue/models.py:25 +msgid "year of birth, range end" +msgstr "rok urodzenia, koniec zakresu" + +#: catalogue/models.py:26 +msgid "date_of_birth" +msgstr "data urodzenia" + +#: catalogue/models.py:29 msgid "place of birth" msgstr "miejsce urodzenia" -#: catalogue/models.py:25 +#: catalogue/models.py:32 msgid "year of death" msgstr "rok śmierci" -#: catalogue/models.py:26 +#: catalogue/models.py:34 +msgid "year of death, range end" +msgstr "rok śmierci, koniec zakresu" + +#: catalogue/models.py:35 +msgid "date_of_death" +msgstr "data śmierci" + +#: catalogue/models.py:38 msgid "place of death" msgstr "miejsce śmierci" -#: catalogue/models.py:28 +#: catalogue/models.py:42 msgid "status" msgstr "status" -#: catalogue/models.py:32 +#: catalogue/models.py:46 msgid "Alive" msgstr "Żyje" -#: catalogue/models.py:33 +#: catalogue/models.py:47 msgid "Dead" msgstr "Zmarły" -#: catalogue/models.py:34 +#: catalogue/models.py:48 msgid "Long dead" msgstr "Dawno zmarły" -#: catalogue/models.py:35 +#: catalogue/models.py:49 msgid "Unknown" msgstr "Nieznany" -#: catalogue/models.py:38 catalogue/models.py:141 catalogue/models.py:207 -#: catalogue/models.py:225 +#: catalogue/models.py:52 catalogue/models.py:162 catalogue/models.py:228 +#: catalogue/models.py:246 msgid "notes" msgstr "notatki" -#: catalogue/models.py:39 catalogue/models.py:147 +#: catalogue/models.py:53 catalogue/models.py:168 msgid "gazeta link" msgstr "link do bazy gazety" -#: catalogue/models.py:40 +#: catalogue/models.py:54 msgid "culture.pl link" msgstr "link do bazy culture.pl" -#: catalogue/models.py:42 +#: catalogue/models.py:56 msgid "description" msgstr "opis" -#: catalogue/models.py:47 catalogue/models.py:143 catalogue/models.py:275 +#: catalogue/models.py:59 catalogue/models.py:164 catalogue/models.py:296 msgid "priority" msgstr "priorytet" -#: catalogue/models.py:48 catalogue/models.py:144 +#: catalogue/models.py:60 catalogue/models.py:165 msgid "Low" msgstr "Niski" -#: catalogue/models.py:48 catalogue/models.py:144 +#: catalogue/models.py:60 catalogue/models.py:165 msgid "Medium" msgstr "Średni" -#: catalogue/models.py:48 catalogue/models.py:144 +#: catalogue/models.py:60 catalogue/models.py:165 msgid "High" msgstr "Wysoki" -#: catalogue/models.py:50 catalogue/models.py:148 catalogue/models.py:230 -#: catalogue/models.py:282 +#: catalogue/models.py:62 catalogue/models.py:169 catalogue/models.py:251 +#: catalogue/models.py:303 msgid "collections" msgstr "kolekcje" -#: catalogue/models.py:53 +#: catalogue/models.py:65 msgid "author" msgstr "autor" -#: catalogue/models.py:54 catalogue/models.py:122 +#: catalogue/models.py:66 catalogue/models.py:143 msgid "authors" msgstr "autorzy" -#: catalogue/models.py:93 catalogue/models.py:205 catalogue/models.py:222 -#: catalogue/models.py:255 +#: catalogue/models.py:114 catalogue/models.py:226 catalogue/models.py:243 +#: catalogue/models.py:276 catalogue/models.py:329 msgid "name" msgstr "nazwa" -#: catalogue/models.py:104 +#: catalogue/models.py:125 msgid "epoch" msgstr "epoka" -#: catalogue/models.py:105 catalogue/models.py:130 catalogue/models.py:279 +#: catalogue/models.py:126 catalogue/models.py:151 catalogue/models.py:300 msgid "epochs" msgstr "epoki" -#: catalogue/models.py:110 +#: catalogue/models.py:131 msgid "genre" msgstr "gatunek" -#: catalogue/models.py:111 catalogue/models.py:132 catalogue/models.py:281 +#: catalogue/models.py:132 catalogue/models.py:153 catalogue/models.py:302 msgid "genres" msgstr "gatunki" -#: catalogue/models.py:116 +#: catalogue/models.py:137 msgid "kind" msgstr "rodzaj" -#: catalogue/models.py:117 catalogue/models.py:131 catalogue/models.py:280 +#: catalogue/models.py:138 catalogue/models.py:152 catalogue/models.py:301 msgid "kinds" msgstr "rodzaje" -#: catalogue/models.py:128 +#: catalogue/models.py:149 msgid "translators" msgstr "tłumacze" -#: catalogue/models.py:133 +#: catalogue/models.py:154 msgid "title" msgstr "tytuł" -#: catalogue/models.py:134 +#: catalogue/models.py:155 msgid "language" msgstr "język" -#: catalogue/models.py:137 +#: catalogue/models.py:158 msgid "based on" msgstr "oparte na" -#: catalogue/models.py:140 +#: catalogue/models.py:161 msgid "text source" msgstr "źródło tekstu" -#: catalogue/models.py:146 +#: catalogue/models.py:167 msgid "year of entry into PD" msgstr "rok wstąpienia do DP" -#: catalogue/models.py:150 +#: catalogue/models.py:171 msgid "estimated number of characters" msgstr "szacowana liczba znaków" -#: catalogue/models.py:151 +#: catalogue/models.py:172 msgid "estimated number of verses" msgstr "szacowana liczba wersów" -#: catalogue/models.py:152 +#: catalogue/models.py:173 msgid "source of estimates" msgstr "źródło szacunków" -#: catalogue/models.py:154 +#: catalogue/models.py:175 msgid "free license" msgstr "wolna licencja" -#: catalogue/models.py:155 +#: catalogue/models.py:176 msgid "missing on Polona" msgstr "brak na Polonie" -#: catalogue/models.py:159 +#: catalogue/models.py:180 msgid "book" msgstr "książka" -#: catalogue/models.py:160 +#: catalogue/models.py:181 msgid "books" msgstr "książki" -#: catalogue/models.py:190 +#: catalogue/models.py:211 msgid "Author" msgstr "autor" -#: catalogue/models.py:195 +#: catalogue/models.py:216 msgid "Translator" msgstr "tłumacze" -#: catalogue/models.py:206 +#: catalogue/models.py:227 msgid "parent" msgstr "rodzic" -#: catalogue/models.py:211 +#: catalogue/models.py:232 msgid "collection category" msgstr "kategoria kolekcji" -#: catalogue/models.py:212 +#: catalogue/models.py:233 msgid "collection categories" msgstr "kategorie kolekcji" -#: catalogue/models.py:224 +#: catalogue/models.py:245 msgid "category" msgstr "kategoria" -#: catalogue/models.py:229 +#: catalogue/models.py:250 msgid "collection" msgstr "kolekcja" -#: catalogue/models.py:259 catalogue/models.py:278 +#: catalogue/models.py:280 catalogue/models.py:299 msgid "work type" msgstr "rodzaj pracy" -#: catalogue/models.py:260 +#: catalogue/models.py:281 msgid "work types" msgstr "rodzaje prac" -#: catalogue/models.py:276 +#: catalogue/models.py:297 msgid "per normalized page" msgstr "za stronę maszynopisu" -#: catalogue/models.py:277 +#: catalogue/models.py:298 msgid "per verse" msgstr "za wers" -#: catalogue/models.py:286 +#: catalogue/models.py:307 msgid "work rate" msgstr "stawka" -#: catalogue/models.py:287 +#: catalogue/models.py:308 msgid "work rates" msgstr "stawki" +#: catalogue/models.py:330 +msgid "locative" +msgstr "miejscownik" + +#: catalogue/models.py:330 +msgid "in…" +msgstr "w…" + +#: catalogue/models.py:333 +msgid "place" +msgstr "miejsce" + +#: catalogue/models.py:334 +msgid "places" +msgstr "miejsca" + #: catalogue/templates/catalogue/author_detail.html:7 #: catalogue/templates/catalogue/author_detail.html:13 #: catalogue/templates/catalogue/book_detail.html:7 diff --git a/src/catalogue/migrations/0035_place_remove_author_place_of_birth_and_more.py b/src/catalogue/migrations/0035_place_remove_author_place_of_birth_and_more.py new file mode 100644 index 00000000..339af8f6 --- /dev/null +++ b/src/catalogue/migrations/0035_place_remove_author_place_of_birth_and_more.py @@ -0,0 +1,83 @@ +# Generated by Django 4.0.6 on 2022-09-22 14:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('catalogue', '0034_notablebook'), + ] + + operations = [ + migrations.CreateModel( + name='Place', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('wikidata', models.CharField(blank=True, help_text='If you have a Wikidata ID, like "Q1337", enter it and save.', max_length=255)), + ('name', models.CharField(blank=True, max_length=255, verbose_name='name')), + ('name_pl', models.CharField(blank=True, max_length=255, null=True, verbose_name='name')), + ('name_de', models.CharField(blank=True, max_length=255, null=True, verbose_name='name')), + ('name_lt', models.CharField(blank=True, max_length=255, null=True, verbose_name='name')), + ('locative', models.CharField(blank=True, help_text='in…', max_length=255, verbose_name='locative')), + ('locative_pl', models.CharField(blank=True, help_text='in…', max_length=255, null=True, verbose_name='locative')), + ('locative_de', models.CharField(blank=True, help_text='in…', max_length=255, null=True, verbose_name='locative')), + ('locative_lt', models.CharField(blank=True, help_text='in…', max_length=255, null=True, verbose_name='locative')), + ], + options={ + 'abstract': False, + }, + ), + migrations.RemoveField( + model_name='author', + name='place_of_birth', + ), + migrations.RemoveField( + model_name='author', + name='place_of_birth_de', + ), + migrations.RemoveField( + model_name='author', + name='place_of_birth_lt', + ), + migrations.RemoveField( + model_name='author', + name='place_of_birth_pl', + ), + migrations.RemoveField( + model_name='author', + name='place_of_death', + ), + migrations.RemoveField( + model_name='author', + name='place_of_death_de', + ), + migrations.RemoveField( + model_name='author', + name='place_of_death_lt', + ), + migrations.RemoveField( + model_name='author', + name='place_of_death_pl', + ), + migrations.AddField( + model_name='author', + name='date_of_birth', + field=models.DateField(blank=True, null=True, verbose_name='date_of_birth'), + ), + migrations.AddField( + model_name='author', + name='date_of_death', + field=models.DateField(blank=True, null=True, verbose_name='date_of_death'), + ), + migrations.AddField( + model_name='author', + name='year_of_birth_range', + field=models.SmallIntegerField(blank=True, null=True, verbose_name='year of birth, range end'), + ), + migrations.AddField( + model_name='author', + name='year_of_death_range', + field=models.SmallIntegerField(blank=True, null=True, verbose_name='year of death, range end'), + ), + ] diff --git a/src/catalogue/migrations/0036_author_place_of_birth_author_place_of_death.py b/src/catalogue/migrations/0036_author_place_of_birth_author_place_of_death.py new file mode 100644 index 00000000..b72e4ba0 --- /dev/null +++ b/src/catalogue/migrations/0036_author_place_of_birth_author_place_of_death.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.6 on 2022-09-22 14:57 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('catalogue', '0035_place_remove_author_place_of_birth_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='author', + name='place_of_birth', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='authors_born', to='catalogue.place', verbose_name='place of birth'), + ), + migrations.AddField( + model_name='author', + name='place_of_death', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='authors_died', to='catalogue.place', verbose_name='place of death'), + ), + ] diff --git a/src/catalogue/migrations/0037_alter_place_options_author_year_of_birth_inexact_and_more.py b/src/catalogue/migrations/0037_alter_place_options_author_year_of_birth_inexact_and_more.py new file mode 100644 index 00000000..e5c5629b --- /dev/null +++ b/src/catalogue/migrations/0037_alter_place_options_author_year_of_birth_inexact_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 4.0.6 on 2022-09-22 15:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('catalogue', '0036_author_place_of_birth_author_place_of_death'), + ] + + operations = [ + migrations.AlterModelOptions( + name='place', + options={'verbose_name': 'place', 'verbose_name_plural': 'places'}, + ), + migrations.AddField( + model_name='author', + name='year_of_birth_inexact', + field=models.BooleanField(default=False, verbose_name='inexact'), + ), + migrations.AddField( + model_name='author', + name='year_of_death_inexact', + field=models.BooleanField(default=False, verbose_name='inexact'), + ), + ] diff --git a/src/catalogue/models.py b/src/catalogue/models.py index d0698808..d671425d 100644 --- a/src/catalogue/models.py +++ b/src/catalogue/models.py @@ -21,9 +21,23 @@ class Author(WikidataMixin, models.Model): gender = models.CharField(_("gender"), max_length=255, blank=True) nationality = models.CharField(_("nationality"), max_length=255, blank=True) year_of_birth = models.SmallIntegerField(_("year of birth"), null=True, blank=True) - place_of_birth = models.CharField(_('place of birth'), max_length=255, blank=True) + year_of_birth_inexact = models.BooleanField(_("inexact"), default=False) + year_of_birth_range = models.SmallIntegerField(_("year of birth, range end"), null=True, blank=True) + date_of_birth = models.DateField(_("date_of_birth"), null=True, blank=True) + place_of_birth = models.ForeignKey( + 'Place', models.PROTECT, null=True, blank=True, + verbose_name=_('place of birth'), + related_name='authors_born' + ) year_of_death = models.SmallIntegerField(_("year of death"), null=True, blank=True) - place_of_death = models.CharField(_('place of death'), max_length=255, blank=True) + year_of_death_inexact = models.BooleanField(_("inexact"), default=False) + year_of_death_range = models.SmallIntegerField(_("year of death, range end"), null=True, blank=True) + date_of_death = models.DateField(_("date_of_death"), null=True, blank=True) + place_of_death = models.ForeignKey( + 'Place', models.PROTECT, null=True, blank=True, + verbose_name=_('place of death'), + related_name='authors_died' + ) status = models.PositiveSmallIntegerField( _("status"), null=True, @@ -55,10 +69,19 @@ class Author(WikidataMixin, models.Model): class Wikidata: first_name = WIKIDATA.GIVEN_NAME last_name = WIKIDATA.LAST_NAME + date_of_birth = WIKIDATA.DATE_OF_BIRTH + year_of_birth = WIKIDATA.DATE_OF_BIRTH + place_of_birth = WIKIDATA.PLACE_OF_BIRTH + date_of_death = WIKIDATA.DATE_OF_DEATH year_of_death = WIKIDATA.DATE_OF_DEATH + place_of_death = WIKIDATA.PLACE_OF_DEATH gender = WIKIDATA.GENDER notes = "description" + def _supplement(obj): + if not obj.first_name and not obj.last_name: + yield 'first_name', 'label' + def __str__(self): name = f"{self.first_name} {self.last_name}" if self.year_of_death is not None: @@ -169,10 +192,10 @@ class Book(WikidataMixin, models.Model): txt = self.title astr = self.authors_str() if astr: - txt = f"{astr} – {txt}" + txt = f"{txt}, {astr}" tstr = self.translators_str() if tstr: - txt = f"{txt} (tłum. {tstr})" + txt = f"{txt}, tłum. {tstr}" return txt def get_absolute_url(self): @@ -301,3 +324,17 @@ class WorkRate(models.Model): if book.estimated_chars: return (decimal.Decimal(book.estimated_chars) / 1800 * self.per_normpage).quantize(decimal.Decimal('1.00'), rounding=decimal.ROUND_HALF_UP) + +class Place(WikidataMixin, models.Model): + name = models.CharField(_('name'), max_length=255, blank=True) + locative = models.CharField(_('locative'), max_length=255, blank=True, help_text=_('in…')) + + class Meta: + verbose_name = _('place') + verbose_name_plural = _('places') + + class Wikidata: + name = 'label' + + def __str__(self): + return self.name diff --git a/src/catalogue/translation.py b/src/catalogue/translation.py index 0ee80711..9637e55d 100644 --- a/src/catalogue/translation.py +++ b/src/catalogue/translation.py @@ -7,7 +7,13 @@ class AuthorTranslationOptions(TranslationOptions): fields = ( 'first_name', 'last_name', - 'place_of_birth', - 'place_of_death', 'description', ) + + +@register(models.Place) +class PlaceTranslationOptions(TranslationOptions): + fields = ( + 'name', + 'locative', + ) diff --git a/src/catalogue/wikidata.py b/src/catalogue/wikidata.py index 4fc8bbd8..610245d5 100644 --- a/src/catalogue/wikidata.py +++ b/src/catalogue/wikidata.py @@ -21,6 +21,28 @@ class WikidataMixin(models.Model): class Meta: abstract = True + def wikidata_populate(self, client, entity, attname, wd): + model_field = self._meta.get_field(attname) + if isinstance(model_field, models.ManyToManyField): + if getattr(self, attname).all().exists(): + return + else: + if getattr(self, attname): + return + + wdvalue = None + if wd == "description": + wdvalue = entity.description.get("pl", str(entity.description)) + elif wd == "label": + wdvalue = entity.label.get("pl", str(entity.label)) + else: + try: + wdvalue = entity.get(client.get(wd)) + except DatavalueError: + pass + + self.set_field_from_wikidata(attname, wdvalue) + def save(self, **kwargs): super().save() if self.wikidata and hasattr(self, "Wikidata"): @@ -33,26 +55,11 @@ class WikidataMixin(models.Model): continue wd = getattr(Wikidata, attname) - model_field = self._meta.get_field(attname) - if isinstance(model_field, models.ManyToManyField): - if getattr(self, attname).all().exists(): - continue - else: - if getattr(self, attname): - continue - - wdvalue = None - if wd == "description": - wdvalue = entity.description.get("pl", str(entity.description)) - elif wd == "label": - wdvalue = entity.label.get("pl", str(entity.label)) - else: - try: - wdvalue = entity.get(client.get(wd)) - except DatavalueError: - pass + self.wikidata_populate(client, entity, attname, wd) + if hasattr(Wikidata, '_supplement'): + for attname, wd in Wikidata._supplement(self): + self.wikidata_populate(client, entity, attname, wd) - self.set_field_from_wikidata(attname, wdvalue) kwargs.update(force_insert=False, force_update=True) super().save(**kwargs)