prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Automatically run populate_next_chant_fields in staging/production
  We need to have some automation to run `python manage.py populate_next_chant_fields` from time to time on our servers; otherwise, the function in /next_chants.py will not work.
  
  </issue>
  <code>
  [start of django/cantusdb_project/main_app/signals.py]
  1 import operator
  2 from functools import reduce
  3 
  4 from django.contrib.postgres.search import SearchVector
  5 from django.db import models
  6 from django.db.models import Value
  7 from django.db.models.signals import post_save, post_delete
  8 from django.dispatch import receiver
  9 
  10 from main_app.models import Chant
  11 from main_app.models import Sequence
  12 
  13 
  14 @receiver(post_save, sender=Chant)
  15 def update_chant_search_vector(instance, **kwargs):
  16     """When saving an instance of Chant, update its search vector field."""
  17     index_components = instance.index_components()
  18     pk = instance.pk
  19     search_vectors = []
  20 
  21     for weight, data in index_components.items():
  22         search_vectors.append(
  23             SearchVector(
  24                 Value(data, output_field=models.TextField()), weight=weight
  25             )
  26         )
  27     instance.__class__.objects.filter(pk=pk).update(
  28         search_vector=reduce(operator.add, search_vectors)
  29     )
  30 
  31 @receiver(post_save, sender=Chant)
  32 @receiver(post_save, sender=Sequence)
  33 @receiver(post_delete, sender=Chant)
  34 @receiver(post_delete, sender=Sequence)
  35 def update_source_chant_count(instance, **kwargs):
  36     """When saving or deleting a Chant or Sequence, update its Source's number_of_chants field"""
  37     source = instance.source
  38     source.number_of_chants = source.chant_set.count() + source.sequence_set.count()
  39     source.save()
  40 
  41 @receiver(post_save, sender=Chant)
  42 @receiver(post_delete, sender=Chant)
  43 def update_source_melody_count(instance, **kwargs):
  44     """When saving or deleting a Chant, update its Source's number_of_melodies field"""
  45     source = instance.source
  46     source.number_of_melodies = source.chant_set.filter(volpiano__isnull=False).count()
  47     source.save()
  48
  [end of django/cantusdb_project/main_app/signals.py]
  [start of django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py]
  1 from main_app.models import Chant
  2 from django.core.exceptions import ValidationError
  3 from django.core.management.base import BaseCommand
  4 
  5 class Command(BaseCommand):
  6     def add_arguments(self, parser):
  7         parser.add_argument(
  8             "-o",
  9             "--overwrite", 
  10             action="store_true", 
  11             help="Overwrites next_chant of chants that already have a next_chant set."
  12             )
  13 
  14     def handle(self, *args, **kwargs):
  15         CHUNK_SIZE = 1_000
  16         overwrite = kwargs["overwrite"]
  17         chants = Chant.objects.all()
  18         chants_count = chants.count()
  19         start_index = 0
  20         while start_index <= chants_count:
  21             print("processing chunk with start_index of", start_index)
  22             chunk = chants[start_index:start_index+CHUNK_SIZE]
  23             for chant in chunk:
  24                 if chant.next_chant and not overwrite: # unless -o or -overwrite flag has been supplied, skip chants that already have a next_chant
  25                     continue
  26                 try:
  27                     chant.next_chant = chant.get_next_chant()
  28                     chant.save()
  29                 except ValidationError: # another chant's next_chant already points to this chant's next_chant
  30                     pass
  31             del chunk # make sure we don't use too much RAM
  32             start_index += CHUNK_SIZE
  33 
  34
  [end of django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.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/management/commands/populate_next_chant_fields.py b/django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py
  --- a/django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py
  +++ b/django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py
  @@ -2,6 +2,17 @@
   from django.core.exceptions import ValidationError
   from django.core.management.base import BaseCommand
   
  +# This script memoizes the result of Chant.get_next_chant(), which is expensive
  +# to calculate on the fly, saving it as the Chant's .next_chant property.
  +# This script populates the next_chant field for all chants in the database.
  +# Once it has been calculated once (for example, after importing data
  +# from OldCantus), it shouldn't need to be run again - whenever chants are
  +# created, updated or deleted, the field should be recalculated for all chants
  +# in the source by update_next_chant_fields() in main_app/signals.py.
  +
  +# to calculate all chants' next_chants from scratch: `python manage.py populate_next_chant_fields --overwrite`
  +# to calculate next_chants for all chants that don't already have a next_chant specified: `python manage.py populate_next_chant_fields`
  +
   class Command(BaseCommand):
       def add_arguments(self, parser):
           parser.add_argument(
  diff --git a/django/cantusdb_project/main_app/signals.py b/django/cantusdb_project/main_app/signals.py
  --- a/django/cantusdb_project/main_app/signals.py
  +++ b/django/cantusdb_project/main_app/signals.py
  @@ -45,3 +45,15 @@
       source = instance.source
       source.number_of_melodies = source.chant_set.filter(volpiano__isnull=False).count()
       source.save()
  +
  +@receiver(post_save, sender=Chant)
  +@receiver(post_delete, sender=Chant)
  +def update_next_chant_fields(instance, **kwargs):
  +    """When saving or deleting a Chant, make sure the next_chant of each chant in the source is up-to-date"""
  +    source = instance.source
  +    for chant in source.chant_set.all():
  +        next_chant = chant.get_next_chant()
  +        # use .update() instead of .save() to prevent RecursionError
  +        # (otherwise, saving would trigger @receiver(post_save, ...) again)
  +        Chant.objects.filter(id=chant.id).update(next_chant=next_chant)
  +
  
verification_info: {"golden_diff": "diff --git a/django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py b/django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py\n--- a/django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py\n+++ b/django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py\n@@ -2,6 +2,17 @@\n from django.core.exceptions import ValidationError\n from django.core.management.base import BaseCommand\n \n+# This script memoizes the result of Chant.get_next_chant(), which is expensive\n+# to calculate on the fly, saving it as the Chant's .next_chant property.\n+# This script populates the next_chant field for all chants in the database.\n+# Once it has been calculated once (for example, after importing data\n+# from OldCantus), it shouldn't need to be run again - whenever chants are\n+# created, updated or deleted, the field should be recalculated for all chants\n+# in the source by update_next_chant_fields() in main_app/signals.py.\n+\n+# to calculate all chants' next_chants from scratch: `python manage.py populate_next_chant_fields --overwrite`\n+# to calculate next_chants for all chants that don't already have a next_chant specified: `python manage.py populate_next_chant_fields`\n+\n class Command(BaseCommand):\n     def add_arguments(self, parser):\n         parser.add_argument(\ndiff --git a/django/cantusdb_project/main_app/signals.py b/django/cantusdb_project/main_app/signals.py\n--- a/django/cantusdb_project/main_app/signals.py\n+++ b/django/cantusdb_project/main_app/signals.py\n@@ -45,3 +45,15 @@\n     source = instance.source\n     source.number_of_melodies = source.chant_set.filter(volpiano__isnull=False).count()\n     source.save()\n+\n+@receiver(post_save, sender=Chant)\n+@receiver(post_delete, sender=Chant)\n+def update_next_chant_fields(instance, **kwargs):\n+    \"\"\"When saving or deleting a Chant, make sure the next_chant of each chant in the source is up-to-date\"\"\"\n+    source = instance.source\n+    for chant in source.chant_set.all():\n+        next_chant = chant.get_next_chant()\n+        # use .update() instead of .save() to prevent RecursionError\n+        # (otherwise, saving would trigger @receiver(post_save, ...) again)\n+        Chant.objects.filter(id=chant.id).update(next_chant=next_chant)\n+\n", "issue": "Automatically run populate_next_chant_fields in staging/production\nWe need to have some automation to run `python manage.py populate_next_chant_fields` from time to time on our servers; otherwise, the function in /next_chants.py will not work.\n", "before_files": [{"content": "import operator\nfrom functools import reduce\n\nfrom django.contrib.postgres.search import SearchVector\nfrom django.db import models\nfrom django.db.models import Value\nfrom django.db.models.signals import post_save, post_delete\nfrom django.dispatch import receiver\n\nfrom main_app.models import Chant\nfrom main_app.models import Sequence\n\n\n@receiver(post_save, sender=Chant)\ndef update_chant_search_vector(instance, **kwargs):\n    \"\"\"When saving an instance of Chant, update its search vector field.\"\"\"\n    index_components = instance.index_components()\n    pk = instance.pk\n    search_vectors = []\n\n    for weight, data in index_components.items():\n        search_vectors.append(\n            SearchVector(\n                Value(data, output_field=models.TextField()), weight=weight\n            )\n        )\n    instance.__class__.objects.filter(pk=pk).update(\n        search_vector=reduce(operator.add, search_vectors)\n    )\n\n@receiver(post_save, sender=Chant)\n@receiver(post_save, sender=Sequence)\n@receiver(post_delete, sender=Chant)\n@receiver(post_delete, sender=Sequence)\ndef update_source_chant_count(instance, **kwargs):\n    \"\"\"When saving or deleting a Chant or Sequence, update its Source's number_of_chants field\"\"\"\n    source = instance.source\n    source.number_of_chants = source.chant_set.count() + source.sequence_set.count()\n    source.save()\n\n@receiver(post_save, sender=Chant)\n@receiver(post_delete, sender=Chant)\ndef update_source_melody_count(instance, **kwargs):\n    \"\"\"When saving or deleting a Chant, update its Source's number_of_melodies field\"\"\"\n    source = instance.source\n    source.number_of_melodies = source.chant_set.filter(volpiano__isnull=False).count()\n    source.save()\n", "path": "django/cantusdb_project/main_app/signals.py"}, {"content": "from main_app.models import Chant\nfrom django.core.exceptions import ValidationError\nfrom django.core.management.base import BaseCommand\n\nclass Command(BaseCommand):\n    def add_arguments(self, parser):\n        parser.add_argument(\n            \"-o\",\n            \"--overwrite\", \n            action=\"store_true\", \n            help=\"Overwrites next_chant of chants that already have a next_chant set.\"\n            )\n\n    def handle(self, *args, **kwargs):\n        CHUNK_SIZE = 1_000\n        overwrite = kwargs[\"overwrite\"]\n        chants = Chant.objects.all()\n        chants_count = chants.count()\n        start_index = 0\n        while start_index <= chants_count:\n            print(\"processing chunk with start_index of\", start_index)\n            chunk = chants[start_index:start_index+CHUNK_SIZE]\n            for chant in chunk:\n                if chant.next_chant and not overwrite: # unless -o or -overwrite flag has been supplied, skip chants that already have a next_chant\n                    continue\n                try:\n                    chant.next_chant = chant.get_next_chant()\n                    chant.save()\n                except ValidationError: # another chant's next_chant already points to this chant's next_chant\n                    pass\n            del chunk # make sure we don't use too much RAM\n            start_index += CHUNK_SIZE\n\n", "path": "django/cantusdb_project/main_app/management/commands/populate_next_chant_fields.py"}]}