From 4e1064e9373a436c4c4c6ddad25a25012c91dd97 Mon Sep 17 00:00:00 2001 From: Andrew Hankinson Date: Thu, 8 Aug 2024 15:07:33 +0200 Subject: [PATCH] New: Add views for institutions This PR adds views for institutions, giving them each their own page on the Cantus site. Special care was taken to get the source counts and source links correct for logged in / not logged in users and published / unpublished sources. In addition external authorities are shown -- currently only RISM Online entries are in the external authorities, but others can be added. An entry for DIAMM as an external authority was also added so that links between Cantus and DIAMM are possible. --- .../cantusdb_project/main_app/identifiers.py | 3 + .../main_app/models/institution.py | 1 + .../templates/institution_detail.html | 71 +++++++++++++++++ .../main_app/templates/institution_list.html | 44 +++++++++++ .../main_app/templates/source_detail.html | 4 + django/cantusdb_project/main_app/urls.py | 12 +++ .../main_app/views/institution.py | 77 +++++++++++++++++++ 7 files changed, 212 insertions(+) create mode 100644 django/cantusdb_project/main_app/templates/institution_detail.html create mode 100644 django/cantusdb_project/main_app/templates/institution_list.html create mode 100644 django/cantusdb_project/main_app/views/institution.py diff --git a/django/cantusdb_project/main_app/identifiers.py b/django/cantusdb_project/main_app/identifiers.py index 4ab27e298..b74bd2798 100644 --- a/django/cantusdb_project/main_app/identifiers.py +++ b/django/cantusdb_project/main_app/identifiers.py @@ -5,6 +5,7 @@ class ExternalIdentifiers: GND = 4 BNF = 5 LC = 6 + DIAMM = 7 IDENTIFIER_TYPES = ( @@ -14,6 +15,7 @@ class ExternalIdentifiers: (ExternalIdentifiers.GND, "GND (Gemeinsame Normdatei)"), (ExternalIdentifiers.BNF, "Bibliothèque national de France"), (ExternalIdentifiers.LC, "Library of Congress"), + (ExternalIdentifiers.DIAMM, "Digital Image Archive of Medieval Music"), ) TYPE_PREFIX = { @@ -23,4 +25,5 @@ class ExternalIdentifiers: ExternalIdentifiers.GND: ("dnb", "https://d-nb.info/gnd/"), ExternalIdentifiers.BNF: ("bnf", "https://catalogue.bnf.fr/ark:/12148/cb"), ExternalIdentifiers.LC: ("lc", "https://id.loc.gov/authorities/"), + ExternalIdentifiers.DIAMM: ("diamm", "https://www.diamm.ac.uk/"), } diff --git a/django/cantusdb_project/main_app/models/institution.py b/django/cantusdb_project/main_app/models/institution.py index 28a6f7ea6..350ad7fbb 100644 --- a/django/cantusdb_project/main_app/models/institution.py +++ b/django/cantusdb_project/main_app/models/institution.py @@ -11,6 +11,7 @@ class Institution(BaseModel): class Meta: + ordering = ["country", "city", "name"] constraints = [ CheckConstraint( check=~(Q(is_private_collector=True) & Q(siglum__isnull=False)), diff --git a/django/cantusdb_project/main_app/templates/institution_detail.html b/django/cantusdb_project/main_app/templates/institution_detail.html new file mode 100644 index 000000000..c862ae679 --- /dev/null +++ b/django/cantusdb_project/main_app/templates/institution_detail.html @@ -0,0 +1,71 @@ +{% extends "base.html" %} + +{% block title %} + +{% endblock %} + +{% block content %} +
+ + {% include "global_search_bar.html" %} + +

{{ institution.name }} {% if institution.siglum %}({{ institution.siglum }}){% endif %}

+

{{ institution.city }}, {{ institution.country }}

+ {% if institution_authorities %} +
+
+
+ {% for authority in institution_authorities %} + View this institution in {{ authority.0 }} + {% endfor %} +
+
+ {% endif %} +
+
+ {% if num_cantus_sources > 0 %} +
+
Cantus Database
+ + + + + + + + {% for source in cantus_sources %} + + + + {% endfor %} + +
Shelfmark
+ {{ source.shelfmark }} +
+
+ {% endif %} + + {% if num_bower_sources > 0 %} +
+
Bower Sequence Database
+ + + + + + + + {% for source in bower_sources %} + + + + {% endfor %} + +
Shelfmark
+ {{ source.shelfmark }} +
+
+ {% endif %} +
+
+{% endblock %} \ No newline at end of file diff --git a/django/cantusdb_project/main_app/templates/institution_list.html b/django/cantusdb_project/main_app/templates/institution_list.html new file mode 100644 index 000000000..0bc32c6f3 --- /dev/null +++ b/django/cantusdb_project/main_app/templates/institution_list.html @@ -0,0 +1,44 @@ +{% extends "base.html" %} + +{% block title %} + +{% endblock %} + +{% block content %} +
+ + {% include "global_search_bar.html" %} + +

Institutions

+ Displaying {{ page_obj.start_index }}-{{ page_obj.end_index }} of {{ page_obj.paginator.count }} + + + + + + + + + + + {% for institution in institutions %} + + + + + + + {% endfor %} + +
CountryCityNameSources
+ {{ institution.country }} + + {{ institution.city }} + + + {{ institution.name }} {% if institution.siglum %}({{ institution.siglum }}){% endif %} + + {{ institution.num_sources }}
+ {% include "pagination.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/django/cantusdb_project/main_app/templates/source_detail.html b/django/cantusdb_project/main_app/templates/source_detail.html index 1340829c0..357f5dc46 100644 --- a/django/cantusdb_project/main_app/templates/source_detail.html +++ b/django/cantusdb_project/main_app/templates/source_detail.html @@ -37,6 +37,10 @@

{{ source.heading }}

{% if source.holding_institution %}
Siglum
{{ source.short_heading }}
+
Holding Institution
+
+ {{ source.holding_institution }} +
{% endif %} {% if source.summary %} diff --git a/django/cantusdb_project/main_app/urls.py b/django/cantusdb_project/main_app/urls.py index 864383e11..84eed1f92 100644 --- a/django/cantusdb_project/main_app/urls.py +++ b/django/cantusdb_project/main_app/urls.py @@ -22,6 +22,7 @@ articles_list_export, flatpages_list_export, ) +from main_app.views.institution import InstitutionListView, InstitutionDetailView from main_app.views.redirect import ( redirect_chants, redirect_genre, @@ -254,6 +255,17 @@ IndexerListView.as_view(), name="indexer-list", ), + # institution + path( + "institutions/", + InstitutionListView.as_view(), + name="institution-list", + ), + path( + "institution/", + InstitutionDetailView.as_view(), + name="institution-detail", + ), # notation path( "notation/", diff --git a/django/cantusdb_project/main_app/views/institution.py b/django/cantusdb_project/main_app/views/institution.py new file mode 100644 index 000000000..d9e0fe45e --- /dev/null +++ b/django/cantusdb_project/main_app/views/institution.py @@ -0,0 +1,77 @@ +from django.db.models import Count, Subquery, OuterRef, Aggregate, F, Q, Func +from django.views.generic import DetailView, ListView + +from main_app.identifiers import IDENTIFIER_TYPES, TYPE_PREFIX +from main_app.models import Institution, Source, Segment, InstitutionIdentifier + + +class InstitutionListView(ListView): + model = Institution + context_object_name = "institutions" + paginate_by = 100 + template_name = "institution_list.html" + + def get_queryset(self): + display_unpublished: bool = self.request.user.is_authenticated + + # uses a subquery to get a count of the sources, filtering by published + # sources only it the user is not logged in. + qargs = {"holding_institution": OuterRef("pk")} + if display_unpublished is False: + qargs["published"] = True + + sources = ( + Source.objects.filter(**qargs) + .annotate(c=Func(F("id"), function="COUNT")) + .values("c") + ) + + # Only display institution records if they have sources in them that the user + # can access. + qset = Institution.objects.annotate(num_sources=Subquery(sources)).filter( + num_sources__gt=0 + ) + return qset + + +class InstitutionDetailView(DetailView): + model = Institution + context_object_name = "institution" + template_name = "institution_detail.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + institution = self.get_object() + + # Show the Cantus and Bower sources in separate tables, and pre-format + # the external authority links. + cantus_segment = Segment.objects.get(id=4063) + bower_segment = Segment.objects.get(id=4064) + cantus_sources = Source.objects.filter( + holding_institution=institution, segment=cantus_segment + ).select_related("holding_institution") + bower_sources = Source.objects.filter( + holding_institution=institution, segment=bower_segment + ).select_related("holding_institution") + institution_authorities = InstitutionIdentifier.objects.filter( + institution=institution + ) + + display_unpublished = self.request.user.is_authenticated + if display_unpublished is False: + cantus_sources = cantus_sources.filter(published=True) + bower_sources = bower_sources.filter(published=True) + + formatted_authorities = [] + for authority in institution_authorities: + formatted_authorities.append( + (authority.identifier_label, authority.identifier_url) + ) + + context["cantus_sources"] = cantus_sources + context["num_cantus_sources"] = cantus_sources.count() + context["bower_sources"] = bower_sources + context["num_bower_sources"] = bower_sources.count() + context["institution_authorities"] = formatted_authorities + + return context