Repository: DDMAL/CantusDB

Issue:
Chant search page - why is Office/Mass field not a <select> dropdown?
![Screen Shot 2023-01-27 at 4 25 14 PM](https://user-images.githubusercontent.com/58090591/215203493-a6cae39f-c881-404c-8f23-dfc589823da3.png)

We only have 17 offices/etc. - why is "Office/Mass" not a dropdown, like "Genre" is? The current implementation works when a user enters a value like "L" or "M", but no results are returned when a user enters "Lauds", which is a problem.

Making it a dropdown may make optimizing search times easier as well.

(There's no point of comparison with OldCantus - it doesn't have an "Office/Mass" field on its search page.)


Discussion:

Resolving patch:
diff --git a/django/cantusdb_project/main_app/views/chant.py b/django/cantusdb_project/main_app/views/chant.py
--- a/django/cantusdb_project/main_app/views/chant.py
+++ b/django/cantusdb_project/main_app/views/chant.py
@@ -23,7 +23,7 @@
     ChantProofreadForm,
     ChantEditSyllabificationForm,
 )
-from main_app.models import Chant, Feast, Genre, Source, Sequence, Segment
+from main_app.models import Chant, Feast, Genre, Source, Sequence, Segment, Office
 from align_text_mel import syllabize_text_and_melody, syllabize_text_to_string
 from django.contrib.auth.mixins import LoginRequiredMixin
 from django.http import Http404
@@ -704,6 +704,7 @@ def get_context_data(self, **kwargs) -> dict:
         context = super().get_context_data(**kwargs)
         # Add to context a QuerySet of dicts with id and name of each Genre
         context["genres"] = Genre.objects.all().order_by("name").values("id", "name")
+        context["offices"] = Office.objects.all().order_by("name").values("id", "name")
         context["order"] = self.request.GET.get("order")
         context["sort"] = self.request.GET.get("sort")
 
@@ -808,8 +809,8 @@ def get_queryset(self) -> QuerySet:
             # In that case, we return the all chants + seqs filtered by the search form.
             # For every GET parameter other than incipit, add to the Q object
             if self.request.GET.get("office"):
-                office = self.request.GET.get("office")
-                q_obj_filter &= Q(office__name__icontains=office)
+                office_id = self.request.GET.get("office")
+                q_obj_filter &= Q(office__id=office_id)
             if self.request.GET.get("genre"):
                 genre_id = int(self.request.GET.get("genre"))
                 q_obj_filter &= Q(genre__id=genre_id)
@@ -953,6 +954,7 @@ def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         # Add to context a QuerySet of dicts with id and name of each Genre
         context["genres"] = Genre.objects.all().order_by("name").values("id", "name")
+        context["offices"] = Office.objects.all().order_by("name").values("id", "name")
         context["order"] = self.request.GET.get("order")
         context["sort"] = self.request.GET.get("sort")
         # This is searching in a specific source, pass the source into context
@@ -1014,8 +1016,8 @@ def get_queryset(self) -> QuerySet:
             return Chant.objects.none()
         # For every GET parameter other than incipit, add to the Q object
         if self.request.GET.get("office"):
-            office = self.request.GET.get("office")
-            q_obj_filter &= Q(office__name__icontains=office)
+            office_id = self.request.GET.get("office")
+            q_obj_filter &= Q(office__id=office_id)
         if self.request.GET.get("genre"):
             genre_id = int(self.request.GET.get("genre"))
             q_obj_filter &= Q(genre__id=genre_id)


Test patch:
diff --git a/django/cantusdb_project/main_app/tests/test_views.py b/django/cantusdb_project/main_app/tests/test_views.py
--- a/django/cantusdb_project/main_app/tests/test_views.py
+++ b/django/cantusdb_project/main_app/tests/test_views.py
@@ -797,7 +797,7 @@ def test_search_by_office(self):
         source = make_fake_source(published=True)
         office = make_fake_office()
         chant = Chant.objects.create(source=source, office=office)
-        search_term = get_random_search_term(office.name)
+        search_term = office.id
         response = self.client.get(reverse("chant-search"), {"office": search_term})
         context_chant_id = response.context["chants"][0]["id"]
         self.assertEqual(chant.id, context_chant_id)
@@ -1294,7 +1294,7 @@ def test_column_header_links(self):
         query_keys_and_values = {
             "op": "contains",
             "keyword": search_term,
-            "office": office.name,
+            "office": office.id,
             "genre": genre.id,
             "cantus_id": cantus_id,
             "mode": mode,
@@ -1645,7 +1645,7 @@ def test_search_by_office(self):
         source = make_fake_source()
         office = make_fake_office()
         chant = Chant.objects.create(source=source, office=office)
-        search_term = get_random_search_term(office.name)
+        search_term = office.id
         response = self.client.get(
             reverse("chant-search-ms", args=[source.id]), {"office": search_term}
         )
@@ -2193,7 +2193,7 @@ def test_column_header_links(self):
         query_keys_and_values = {
             "op": "contains",
             "keyword": search_term,
-            "office": office.name,
+            "office": office.id,
             "genre": genre.id,
             "cantus_id": cantus_id,
             "mode": mode,