diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6037c927..806f5217 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,14 +6,35 @@ "features": {}, "customizations": { "vscode": { - "extensions": ["ms-python.python", "ms-python.vscode-pylance"] + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "ms-python.debugpy", + "charliermarsh.ruff" + ], + "settings": { + "python.linting.enabled": true, + "python.linting.lintOnSave": true, + "python.formatting.provider": "none", + "editor.formatOnSave": true, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit" + } + }, + "ruff.lint.run": "onSave", + "ruff.format.args": ["--line-length", "100"], + "ruff.organizeImports": true + } } }, "waitFor": "onCreateCommand", "portsAttributes": { "8000": { - "label": "Application", - "onAutoForward": "openBrowser" + "label": "Application" } }, "forwardPorts": [8000], diff --git a/community/models.py b/community/models.py index 6e823ad6..ba596cf5 100644 --- a/community/models.py +++ b/community/models.py @@ -108,6 +108,12 @@ class OnlineWorshipDayChoices(models.TextChoices): index.SearchField( "description", ), + index.RelatedFields( + "hosted_by", + [ + index.SearchField("title"), + ], + ), ] diff --git a/documents/models.py b/documents/models.py index 6b9b0983..bb46d7fc 100644 --- a/documents/models.py +++ b/documents/models.py @@ -2,6 +2,7 @@ from wagtail.admin.panels import FieldPanel from wagtail.models import Page from wagtail.fields import StreamField, RichTextField +from wagtail.search import index from core.constants import COMMON_STREAMFIELD_BLOCKS from common.models import DrupalFields @@ -78,6 +79,16 @@ class MeetingDocmentTypeChoices(models.TextChoices): FieldPanel("body"), ] + search_fields = Page.search_fields + [ + index.SearchField("body"), + index.RelatedFields( + "publishing_meeting", + [ + index.SearchField("title"), + ], + ), + ] + class Meta: ordering = [ "-publication_date", @@ -111,6 +122,9 @@ class PublicBoardDocumentIndexPage(Page): content_panels = Page.content_panels + [ FieldPanel("intro", classname="full"), ] + search_fields = Page.search_fields + [ + index.SearchField("intro"), + ] class PublicBoardDocument(DrupalFields, Page): @@ -157,6 +171,10 @@ class PublicBoardDocmentCategoryChoices(models.TextChoices): parent_page_types = ["documents.PublicBoardDocumentIndexPage"] subpage_types: list[str] = [] + search_fields = Page.search_fields + [ + index.SearchField("body"), + ] + content_panels = Page.content_panels + [ FieldPanel("category"), FieldPanel("publication_date"), diff --git a/events/models.py b/events/models.py index ec57f3cc..f5bb3d13 100644 --- a/events/models.py +++ b/events/models.py @@ -1,7 +1,7 @@ -from django.utils import timezone from django.db import models from django.db.models import Q from django.http import Http404, HttpRequest +from django.utils import timezone from modelcluster.fields import ParentalKey # type: ignore from timezone_field import TimeZoneField # type: ignore from wagtail.admin.panels import FieldPanel, InlinePanel, PageChooserPanel @@ -90,6 +90,17 @@ class EventCategoryChoices(models.TextChoices): index.SearchField( "body", ), + index.RelatedFields( + "sponsors", + [ + index.RelatedFields( + "sponsor", + [ + index.SearchField("title"), + ], + ), + ], + ), ] parent_page_types = ["events.EventsIndexPage"] @@ -98,6 +109,12 @@ class EventCategoryChoices(models.TextChoices): class Meta: db_table = "events" ordering = ["start_date"] + indexes = [ + # default ordering is by start date + models.Index(fields=["start_date"]), + # Some queries also check the end date + models.Index(fields=["end_date"]), + ] class EventsIndexPage(Page): diff --git a/library/models.py b/library/models.py index 1dba5730..44a3c3a1 100644 --- a/library/models.py +++ b/library/models.py @@ -73,6 +73,8 @@ class LibraryItem(DrupalFields, Page): # type: ignore @classmethod def get_queryset(cls): related_fields = [ + "authors__author", + "topics__topic", "item_audience", "item_genre", "item_medium", @@ -125,6 +127,20 @@ def get_queryset(cls): search_fields = Page.search_fields + [ index.SearchField("body"), + index.RelatedFields( + "authors", + [ + index.RelatedFields( + "author", + [ + # This will cover the name for all Contact types + index.SearchField("title"), + index.SearchField("given_name"), # For Person contacts + index.SearchField("family_name"), # For Person contacts + ], + ), + ], + ), index.RelatedFields( "item_genre", [ diff --git a/magazine/migrations/0034_alter_magazinearticle_options_and_more.py b/magazine/migrations/0034_alter_magazinearticle_options_and_more.py new file mode 100644 index 00000000..29c7aeeb --- /dev/null +++ b/magazine/migrations/0034_alter_magazinearticle_options_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 5.1 on 2024-09-07 07:45 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("magazine", "0033_alter_archivearticle_pdf_page_number_and_more"), + ] + + operations = [ + migrations.AlterModelOptions( + name="magazinearticle", + options={ + "verbose_name": "Magazine Article", + "verbose_name_plural": "Magazine Articles", + }, + ), + migrations.AlterModelOptions( + name="magazinearticleauthor", + options={ + "verbose_name": "Magazine Article Author", + "verbose_name_plural": "Magazine Article Authors", + }, + ), + ] diff --git a/magazine/models.py b/magazine/models.py index d69b581d..2c71b118 100644 --- a/magazine/models.py +++ b/magazine/models.py @@ -139,6 +139,14 @@ class MagazineIssue(DrupalFields, Page): # type: ignore issue_number = models.PositiveIntegerField(null=True, blank=True) drupal_node_id = models.PositiveIntegerField(null=True, blank=True, db_index=True) + @classmethod + def get_queryset(cls): + """TODO: Prefetch related articles for performance.""" + # TODO: Determine if it is possible or necessary to prefech the Articles for performance + # the main difficulty being the implicit relationship between the Issue and the Articles + # since the Articles are children of the Issue + return super().get_queryset() + @property def featured_articles(self) -> QuerySet["MagazineArticle"]: # Return a cursor of related articles that are featured @@ -182,6 +190,10 @@ def is_public_access(self) -> bool: return self.publication_date < ARCHIVE_THRESHOLD_DATE search_template = "search/magazine_issue.html" + search_fields = Page.search_fields + [ + index.SearchField("issue_number"), + index.SearchField("publication_date"), + ] content_panels = Page.content_panels + [ FieldPanel("publication_date", widget=DatePickerInput()), @@ -358,13 +370,27 @@ def get_queryset(cls): return super().get_queryset().prefetch_related(*related_fields) class Meta: - verbose_name = "Page" - verbose_name_plural = "Pages" + verbose_name = "Magazine Article" + verbose_name_plural = "Magazine Articles" search_fields = Page.search_fields + [ + index.SearchField("teaser"), index.SearchField( "body", ), + index.RelatedFields( + "authors", + [ + index.RelatedFields( + "author", + [ + index.SearchField("title"), + index.SearchField("given_name"), + index.SearchField("family_name"), + ], + ), + ], + ), ] content_panels = Page.content_panels + [ @@ -464,8 +490,8 @@ class MagazineArticleAuthor(Orderable): ] class Meta: - verbose_name = "Page" - verbose_name_plural = "Pages" + verbose_name = "Magazine Article Author" + verbose_name_plural = "Magazine Article Authors" class ArchiveArticleAuthor(Orderable): @@ -533,6 +559,22 @@ class ArchiveArticle(ClusterableModel): ), ] + search_fields = Page.search_fields + [ + index.RelatedFields( + "archive_authors", + [ + index.RelatedFields( + "author", + [ + index.SearchField("title"), + index.SearchField("given_name"), + index.SearchField("family_name"), + ], + ), + ], + ), + ] + class Meta: indexes = [ models.Index(fields=["drupal_node_id"]), diff --git a/memorials/models.py b/memorials/models.py index 868b7b81..bc1e4634 100644 --- a/memorials/models.py +++ b/memorials/models.py @@ -4,9 +4,10 @@ from wagtail.admin.panels import FieldPanel, PageChooserPanel from wagtail.fields import RichTextField from wagtail.models import Page +from wagtail.search import index -from contact.models import Meeting from common.models import DrupalFields +from contact.models import Meeting from pagination.helpers import get_paginated_items @@ -29,6 +30,18 @@ class Memorial(DrupalFields, Page): # type: ignore ) drupal_memorial_id = models.PositiveIntegerField(null=True, blank=True) + search_fields = Page.search_fields + [ + index.SearchField("memorial_minute"), + index.RelatedFields( + "memorial_person", + [ + index.SearchField("title"), + index.SearchField("given_name"), + index.SearchField("family_name"), + ], + ), + ] + class Meta: ordering = ( "memorial_person__family_name", @@ -51,10 +64,6 @@ def full_name(self) -> str: "memorials.MemorialIndexPage", ] - # TODO: determine whether we need a search index on any of the fields - # or remove this search fields code - # search_fields = [] - class MemorialIndexPage(Page): intro = RichTextField(blank=True)