Catalogue: nicer browsing of books with just notes.
[redakcja.git] / src / catalogue / admin.py
1 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
3 #
4 from django.contrib import admin
5 from django.utils.html import escape
6 from django.utils.safestring import mark_safe
7 from django.utils.translation import gettext_lazy as _
8 from admin_numeric_filter.admin import RangeNumericFilter, NumericFilterModelAdmin
9 from fnpdjango.actions import export_as_csv_action
10 from . import models
11 from .wikidata import WikidataAdminMixin
12
13
14 class AuthorAdmin(WikidataAdminMixin, admin.ModelAdmin):
15     list_display = [
16         "first_name",
17         "last_name",
18         "status",
19         "year_of_death",
20         "gender",
21         "nationality",
22         "priority",
23         "wikidata_link",
24         "slug",
25     ]
26     list_filter = ["year_of_death", "priority", "collections", "status", "gender", "nationality"]
27     search_fields = ["first_name", "last_name", "wikidata"]
28     prepopulated_fields = {"slug": ("first_name", "last_name")}
29     autocomplete_fields = ["collections"]
30
31
32 admin.site.register(models.Author, AuthorAdmin)
33
34
35 class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin):
36     list_display = [
37         "smart_title",
38         "authors_str",
39         "translators_str",
40         "language",
41         "pd_year",
42         "priority",
43         "wikidata_link",
44     ]
45     search_fields = [
46         "title", "wikidata",
47         "authors__first_name", "authors__last_name",
48         "translators__first_name", "translators__last_name",
49         "scans_source", "text_source", "notes", "estimate_source",
50     ]
51     autocomplete_fields = ["authors", "translators", "based_on", "collections", "epochs", "genres", "kinds"]
52     prepopulated_fields = {"slug": ("title",)}
53     list_filter = [
54         "language",
55         "based_on__language",
56         ("pd_year", RangeNumericFilter),
57         "collections",
58         "collections__category",
59         "epochs", "kinds", "genres",
60         "priority",
61         "authors__gender", "authors__nationality",
62         "translators__gender", "translators__nationality",
63         "document_book__chunk__stage",
64         "document_book__chunk__user",
65     ]
66     readonly_fields = ["wikidata_link", "estimated_costs"]
67     actions = [export_as_csv_action()]
68     fieldsets = [
69         (None, {"fields": [("wikidata", "wikidata_link")]}),
70         (
71             _("Identification"),
72             {
73                 "fields": [
74                     "title",
75                     "slug",
76                     "authors",
77                     "translators",
78                     "language",
79                     "based_on",
80                     "pd_year",
81                 ]
82             },
83         ),
84         (
85             _("Features"),
86             {
87                 "fields": [
88                     "epochs",
89                     "genres",
90                     "kinds",
91                 ]
92             },
93         ),
94         (
95             _("Plan"),
96             {
97                 "fields": [
98                     "scans_source",
99                     "text_source",
100                     "priority",
101                     "collections",
102                     "notes",
103                     ("estimated_chars", "estimated_verses", "estimate_source"),
104                     "estimated_costs",
105                 ]
106             },
107         ),
108     ]
109
110     def get_queryset(self, request):
111         qs = super().get_queryset(request)
112         if request.resolver_match.view_name.endswith("changelist"):
113             qs = qs.prefetch_related("authors", "translators")
114         return qs
115
116     def estimated_costs(self, obj):
117         return "\n".join(
118             "{}: {} zł".format(
119                 work_type.name,
120                 cost or '—'
121             )
122             for work_type, cost in obj.get_estimated_costs().items()
123         )
124
125     def smart_title(self, obj):
126         if obj.title:
127             return obj.title
128         if obj.notes:
129             n = obj.notes
130             if len(n) > 100:
131                 n = n[:100] + '…'
132             return mark_safe(
133                 '<em><small>' + escape(n) + '</small></em>'
134             )
135         return '---'
136     smart_title.short_description = _('Title')
137     smart_title.admin_order_field = 'title'
138     
139
140 admin.site.register(models.Book, BookAdmin)
141
142
143 admin.site.register(models.CollectionCategory)
144
145
146 class AuthorInline(admin.TabularInline):
147     model = models.Author.collections.through
148     autocomplete_fields = ["author"]
149
150
151 class BookInline(admin.TabularInline):
152     model = models.Book.collections.through
153     autocomplete_fields = ["book"]
154
155
156 class CollectionAdmin(admin.ModelAdmin):
157     list_display = ["name"]
158     autocomplete_fields = []
159     prepopulated_fields = {"slug": ("name",)}
160     search_fields = ["name"]
161     fields = ['name', 'slug', 'category', 'notes', 'estimated_costs']
162     readonly_fields = ['estimated_costs']
163     inlines = [AuthorInline, BookInline]
164
165     def estimated_costs(self, obj):
166         return "\n".join(
167             "{}: {} zł".format(
168                 work_type.name,
169                 cost or '—'
170             )
171             for work_type, cost in obj.get_estimated_costs().items()
172         )
173
174
175 admin.site.register(models.Collection, CollectionAdmin)
176
177
178
179 class CategoryAdmin(admin.ModelAdmin):
180     search_fields = ["name"]
181
182 admin.site.register(models.Epoch, CategoryAdmin)
183 admin.site.register(models.Genre, CategoryAdmin)
184 admin.site.register(models.Kind, CategoryAdmin)
185
186
187
188 class WorkRateInline(admin.TabularInline):
189     model = models.WorkRate
190     autocomplete_fields = ['kinds', 'genres', 'epochs', 'collections']
191
192
193 class WorkTypeAdmin(admin.ModelAdmin):
194     inlines = [WorkRateInline]
195
196 admin.site.register(models.WorkType, WorkTypeAdmin)
197