prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Certain Genre Detail pages are _very_ slow to load
  I think the problem is trying to display the "chants by genre" table - for a genre with lots of example chants, e.g. [Antiphon](http://206.12.88.113/genre/122), I've tried loading the page several times and keep getting a 502 error.
  
  </issue>
  <code>
  [start of django/cantusdb_project/main_app/views/genre.py]
  1 from typing import Dict, List
  2 
  3 from django.views.generic import ListView
  4 from django.views.generic.detail import SingleObjectMixin
  5 from extra_views import SearchableListMixin
  6 from main_app.models import Genre
  7 
  8 
  9 class GenreDetailView(SingleObjectMixin, ListView):
  10     paginate_by = 100
  11     template_name = "genre_detail.html"
  12 
  13     def get_genre_cantus_ids(self, display_unpublished=True) -> List[Dict]:
  14         """
  15         Get a list with data on each unique ``cantus_id`` related to this Genre.
  16 
  17         The list contains dicts and each dict has the following keys:
  18 
  19         ``cantus_id``: The ``cantus_id``
  20         ``num_chants``: The number of Chants that have this ``cantus_id``
  21         ``first_incipit``: The incipit of first Chant with this ``cantus_id``
  22         ``first_incipit_url``: The url of first Chant with this ``cantus_id``
  23 
  24         Returns:
  25             List[Dict]: A list of dicts with data on each unique ``cantus_id``
  26         """
  27         cantus_ids = (self.object.chant_set
  28             .exclude(cantus_id=None)
  29             .values_list("cantus_id", flat=True)
  30             .distinct("cantus_id")
  31         )
  32         if not display_unpublished:
  33             cantus_ids = cantus_ids.filter(source__published=True)
  34         
  35         cantus_ids_list = list(cantus_ids)
  36 
  37         chant_list = []
  38         for cantus_id in cantus_ids_list:
  39             chants = self.object.chant_set.filter(cantus_id=cantus_id)
  40             num_chants = chants.count()
  41             first_chant = chants.first()
  42             first_incipit_url = first_chant.get_absolute_url()
  43             first_incipit = first_chant.incipit
  44             chant_list.append(
  45                 {
  46                     "cantus_id": cantus_id,
  47                     "num_chants": num_chants,
  48                     "first_incipit": first_incipit,
  49                     "first_incipit_url": first_incipit_url,
  50                 }
  51             )
  52         # Sort list based on number of Chants per cantus_id (descending)
  53         chant_list = sorted(chant_list, key=lambda k: k["num_chants"], reverse=True)
  54         return chant_list
  55 
  56     def get(self, request, *args, **kwargs):
  57         self.object = self.get_object(queryset=Genre.objects.all())
  58         return super().get(request, *args, **kwargs)
  59 
  60     def get_context_data(self, **kwargs):
  61         context = super().get_context_data(**kwargs)
  62         context["genre"] = self.object
  63         return context
  64 
  65     def get_queryset(self):
  66         display_unpublished = self.request.user.is_authenticated
  67         search_term = self.request.GET.get("incipit")
  68         if not search_term:
  69             return self.get_genre_cantus_ids(display_unpublished=display_unpublished)
  70         else:
  71             search_term = search_term.strip(" ")
  72             filtered_chants = [
  73                 chant
  74                 for chant in self.get_genre_cantus_ids(display_unpublished=display_unpublished)
  75                 if search_term.lower() in chant["first_incipit"].lower()
  76             ]
  77             return filtered_chants
  78 
  79 
  80 class GenreListView(SearchableListMixin, ListView):
  81     model = Genre
  82     paginate_by = 100
  83     context_object_name = "genres"
  84     template_name = "genre_list.html"
  85 
  86     def get_queryset(self):
  87         queryset = super().get_queryset()
  88         mass_office = self.request.GET.get("mass_office", None)
  89         if mass_office in ["Mass", "Office", "Old Hispanic"]:
  90             queryset = queryset.filter(mass_office__contains=mass_office)
  91         return queryset.order_by("name")
  92
  [end of django/cantusdb_project/main_app/views/genre.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/django/cantusdb_project/main_app/views/genre.py b/django/cantusdb_project/main_app/views/genre.py
  --- a/django/cantusdb_project/main_app/views/genre.py
  +++ b/django/cantusdb_project/main_app/views/genre.py
  @@ -1,81 +1,13 @@
  -from typing import Dict, List
  -
  -from django.views.generic import ListView
  -from django.views.generic.detail import SingleObjectMixin
  +from django.views.generic import DetailView, ListView
   from extra_views import SearchableListMixin
   from main_app.models import Genre
   
   
  -class GenreDetailView(SingleObjectMixin, ListView):
  -    paginate_by = 100
  +class GenreDetailView(DetailView):
  +    model = Genre
  +    context_object_name = "genre"
       template_name = "genre_detail.html"
   
  -    def get_genre_cantus_ids(self, display_unpublished=True) -> List[Dict]:
  -        """
  -        Get a list with data on each unique ``cantus_id`` related to this Genre.
  -
  -        The list contains dicts and each dict has the following keys:
  -
  -        ``cantus_id``: The ``cantus_id``
  -        ``num_chants``: The number of Chants that have this ``cantus_id``
  -        ``first_incipit``: The incipit of first Chant with this ``cantus_id``
  -        ``first_incipit_url``: The url of first Chant with this ``cantus_id``
  -
  -        Returns:
  -            List[Dict]: A list of dicts with data on each unique ``cantus_id``
  -        """
  -        cantus_ids = (self.object.chant_set
  -            .exclude(cantus_id=None)
  -            .values_list("cantus_id", flat=True)
  -            .distinct("cantus_id")
  -        )
  -        if not display_unpublished:
  -            cantus_ids = cantus_ids.filter(source__published=True)
  -        
  -        cantus_ids_list = list(cantus_ids)
  -
  -        chant_list = []
  -        for cantus_id in cantus_ids_list:
  -            chants = self.object.chant_set.filter(cantus_id=cantus_id)
  -            num_chants = chants.count()
  -            first_chant = chants.first()
  -            first_incipit_url = first_chant.get_absolute_url()
  -            first_incipit = first_chant.incipit
  -            chant_list.append(
  -                {
  -                    "cantus_id": cantus_id,
  -                    "num_chants": num_chants,
  -                    "first_incipit": first_incipit,
  -                    "first_incipit_url": first_incipit_url,
  -                }
  -            )
  -        # Sort list based on number of Chants per cantus_id (descending)
  -        chant_list = sorted(chant_list, key=lambda k: k["num_chants"], reverse=True)
  -        return chant_list
  -
  -    def get(self, request, *args, **kwargs):
  -        self.object = self.get_object(queryset=Genre.objects.all())
  -        return super().get(request, *args, **kwargs)
  -
  -    def get_context_data(self, **kwargs):
  -        context = super().get_context_data(**kwargs)
  -        context["genre"] = self.object
  -        return context
  -
  -    def get_queryset(self):
  -        display_unpublished = self.request.user.is_authenticated
  -        search_term = self.request.GET.get("incipit")
  -        if not search_term:
  -            return self.get_genre_cantus_ids(display_unpublished=display_unpublished)
  -        else:
  -            search_term = search_term.strip(" ")
  -            filtered_chants = [
  -                chant
  -                for chant in self.get_genre_cantus_ids(display_unpublished=display_unpublished)
  -                if search_term.lower() in chant["first_incipit"].lower()
  -            ]
  -            return filtered_chants
  -
   
   class GenreListView(SearchableListMixin, ListView):
       model = Genre
  
verification_info: {"golden_diff": "diff --git a/django/cantusdb_project/main_app/views/genre.py b/django/cantusdb_project/main_app/views/genre.py\n--- a/django/cantusdb_project/main_app/views/genre.py\n+++ b/django/cantusdb_project/main_app/views/genre.py\n@@ -1,81 +1,13 @@\n-from typing import Dict, List\n-\n-from django.views.generic import ListView\n-from django.views.generic.detail import SingleObjectMixin\n+from django.views.generic import DetailView, ListView\n from extra_views import SearchableListMixin\n from main_app.models import Genre\n \n \n-class GenreDetailView(SingleObjectMixin, ListView):\n-    paginate_by = 100\n+class GenreDetailView(DetailView):\n+    model = Genre\n+    context_object_name = \"genre\"\n     template_name = \"genre_detail.html\"\n \n-    def get_genre_cantus_ids(self, display_unpublished=True) -> List[Dict]:\n-        \"\"\"\n-        Get a list with data on each unique ``cantus_id`` related to this Genre.\n-\n-        The list contains dicts and each dict has the following keys:\n-\n-        ``cantus_id``: The ``cantus_id``\n-        ``num_chants``: The number of Chants that have this ``cantus_id``\n-        ``first_incipit``: The incipit of first Chant with this ``cantus_id``\n-        ``first_incipit_url``: The url of first Chant with this ``cantus_id``\n-\n-        Returns:\n-            List[Dict]: A list of dicts with data on each unique ``cantus_id``\n-        \"\"\"\n-        cantus_ids = (self.object.chant_set\n-            .exclude(cantus_id=None)\n-            .values_list(\"cantus_id\", flat=True)\n-            .distinct(\"cantus_id\")\n-        )\n-        if not display_unpublished:\n-            cantus_ids = cantus_ids.filter(source__published=True)\n-        \n-        cantus_ids_list = list(cantus_ids)\n-\n-        chant_list = []\n-        for cantus_id in cantus_ids_list:\n-            chants = self.object.chant_set.filter(cantus_id=cantus_id)\n-            num_chants = chants.count()\n-            first_chant = chants.first()\n-            first_incipit_url = first_chant.get_absolute_url()\n-            first_incipit = first_chant.incipit\n-            chant_list.append(\n-                {\n-                    \"cantus_id\": cantus_id,\n-                    \"num_chants\": num_chants,\n-                    \"first_incipit\": first_incipit,\n-                    \"first_incipit_url\": first_incipit_url,\n-                }\n-            )\n-        # Sort list based on number of Chants per cantus_id (descending)\n-        chant_list = sorted(chant_list, key=lambda k: k[\"num_chants\"], reverse=True)\n-        return chant_list\n-\n-    def get(self, request, *args, **kwargs):\n-        self.object = self.get_object(queryset=Genre.objects.all())\n-        return super().get(request, *args, **kwargs)\n-\n-    def get_context_data(self, **kwargs):\n-        context = super().get_context_data(**kwargs)\n-        context[\"genre\"] = self.object\n-        return context\n-\n-    def get_queryset(self):\n-        display_unpublished = self.request.user.is_authenticated\n-        search_term = self.request.GET.get(\"incipit\")\n-        if not search_term:\n-            return self.get_genre_cantus_ids(display_unpublished=display_unpublished)\n-        else:\n-            search_term = search_term.strip(\" \")\n-            filtered_chants = [\n-                chant\n-                for chant in self.get_genre_cantus_ids(display_unpublished=display_unpublished)\n-                if search_term.lower() in chant[\"first_incipit\"].lower()\n-            ]\n-            return filtered_chants\n-\n \n class GenreListView(SearchableListMixin, ListView):\n     model = Genre\n", "issue": "Certain Genre Detail pages are _very_ slow to load\nI think the problem is trying to display the \"chants by genre\" table - for a genre with lots of example chants, e.g. [Antiphon](http://206.12.88.113/genre/122), I've tried loading the page several times and keep getting a 502 error.\n", "before_files": [{"content": "from typing import Dict, List\n\nfrom django.views.generic import ListView\nfrom django.views.generic.detail import SingleObjectMixin\nfrom extra_views import SearchableListMixin\nfrom main_app.models import Genre\n\n\nclass GenreDetailView(SingleObjectMixin, ListView):\n    paginate_by = 100\n    template_name = \"genre_detail.html\"\n\n    def get_genre_cantus_ids(self, display_unpublished=True) -> List[Dict]:\n        \"\"\"\n        Get a list with data on each unique ``cantus_id`` related to this Genre.\n\n        The list contains dicts and each dict has the following keys:\n\n        ``cantus_id``: The ``cantus_id``\n        ``num_chants``: The number of Chants that have this ``cantus_id``\n        ``first_incipit``: The incipit of first Chant with this ``cantus_id``\n        ``first_incipit_url``: The url of first Chant with this ``cantus_id``\n\n        Returns:\n            List[Dict]: A list of dicts with data on each unique ``cantus_id``\n        \"\"\"\n        cantus_ids = (self.object.chant_set\n            .exclude(cantus_id=None)\n            .values_list(\"cantus_id\", flat=True)\n            .distinct(\"cantus_id\")\n        )\n        if not display_unpublished:\n            cantus_ids = cantus_ids.filter(source__published=True)\n        \n        cantus_ids_list = list(cantus_ids)\n\n        chant_list = []\n        for cantus_id in cantus_ids_list:\n            chants = self.object.chant_set.filter(cantus_id=cantus_id)\n            num_chants = chants.count()\n            first_chant = chants.first()\n            first_incipit_url = first_chant.get_absolute_url()\n            first_incipit = first_chant.incipit\n            chant_list.append(\n                {\n                    \"cantus_id\": cantus_id,\n                    \"num_chants\": num_chants,\n                    \"first_incipit\": first_incipit,\n                    \"first_incipit_url\": first_incipit_url,\n                }\n            )\n        # Sort list based on number of Chants per cantus_id (descending)\n        chant_list = sorted(chant_list, key=lambda k: k[\"num_chants\"], reverse=True)\n        return chant_list\n\n    def get(self, request, *args, **kwargs):\n        self.object = self.get_object(queryset=Genre.objects.all())\n        return super().get(request, *args, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context[\"genre\"] = self.object\n        return context\n\n    def get_queryset(self):\n        display_unpublished = self.request.user.is_authenticated\n        search_term = self.request.GET.get(\"incipit\")\n        if not search_term:\n            return self.get_genre_cantus_ids(display_unpublished=display_unpublished)\n        else:\n            search_term = search_term.strip(\" \")\n            filtered_chants = [\n                chant\n                for chant in self.get_genre_cantus_ids(display_unpublished=display_unpublished)\n                if search_term.lower() in chant[\"first_incipit\"].lower()\n            ]\n            return filtered_chants\n\n\nclass GenreListView(SearchableListMixin, ListView):\n    model = Genre\n    paginate_by = 100\n    context_object_name = \"genres\"\n    template_name = \"genre_list.html\"\n\n    def get_queryset(self):\n        queryset = super().get_queryset()\n        mass_office = self.request.GET.get(\"mass_office\", None)\n        if mass_office in [\"Mass\", \"Office\", \"Old Hispanic\"]:\n            queryset = queryset.filter(mass_office__contains=mass_office)\n        return queryset.order_by(\"name\")\n", "path": "django/cantusdb_project/main_app/views/genre.py"}]}