From c97b66a983edc689ed840bd89504bb83864043f4 Mon Sep 17 00:00:00 2001 From: Greg Kempe Date: Fri, 21 Jul 2023 10:55:21 +0200 Subject: [PATCH] Use through model on judgment.judges to preserve ordering This way, the order in which the judges are added to the decision in the admin area is preserved when presented to the user. We don't have to explicitly add an ordering field -- the editor must just enter the judges in the correct order. We need to tweak some of the older migrations to work with theh existing data, since nothing is changing under the hood. Only Django's view of the database and how it works with it is changing. --- peachjam/admin.py | 20 +++++++-- ...ent_judgmentmediasummaryfile_mattertype.py | 44 ++++++++++++++++++- peachjam/migrations/0042_i18n_models.py | 5 ++- .../migrations/0092_alter_judge_options.py | 21 +++++++++ peachjam/models/judgment.py | 32 +++++++++++--- .../peachjam/layouts/document_detail.html | 6 +-- 6 files changed, 114 insertions(+), 14 deletions(-) create mode 100644 peachjam/migrations/0092_alter_judge_options.py diff --git a/peachjam/admin.py b/peachjam/admin.py index 0a79f1999..d49a1e967 100644 --- a/peachjam/admin.py +++ b/peachjam/admin.py @@ -36,6 +36,7 @@ AttachedFiles, Attorney, Author, + Bench, Book, CaseNumber, CitationLink, @@ -586,6 +587,14 @@ class AttachedFilesInline(BaseAttachmentFileInline): form = AttachedFilesForm +class BenchInline(admin.TabularInline): + # by using an inline, the ordering of the judges is preserved + model = Bench + extra = 3 + verbose_name = gettext_lazy("judge") + verbose_name_plural = gettext_lazy("judges") + + class JudgmentAdminForm(DocumentForm): hearing_date = forms.DateField(widget=DateSelectorWidget(), required=False) @@ -607,7 +616,11 @@ def save(self, *args, **kwargs): class JudgmentAdmin(ImportExportMixin, DocumentAdmin): form = JudgmentAdminForm resource_class = JudgmentResource - inlines = [CaseNumberAdmin, AttachedFilesInline] + DocumentAdmin.inlines + inlines = [ + BenchInline, + CaseNumberAdmin, + AttachedFilesInline, + ] + DocumentAdmin.inlines filter_horizontal = ("judges", "attorneys") list_filter = (*DocumentAdmin.list_filter, "court") fieldsets = copy.deepcopy(DocumentAdmin.fieldsets) @@ -620,8 +633,7 @@ class JudgmentAdmin(ImportExportMixin, DocumentAdmin): fieldsets[0][1]["fields"].insert(8, "serial_number_override") fieldsets[0][1]["fields"].insert(9, "serial_number") fieldsets[0][1]["fields"].append("hearing_date") - fieldsets[1][1]["fields"].insert(0, "judges") - fieldsets[1][1]["fields"].insert(1, "attorneys") + fieldsets[1][1]["fields"].insert(0, "attorneys") fieldsets[2][1]["classes"] = ["collapse"] fieldsets[3][1]["fields"].extend( @@ -650,7 +662,7 @@ class PredicateAdmin(admin.ModelAdmin): class IngestorSettingInline(admin.TabularInline): model = IngestorSetting - extra = 1 + extra = 3 @admin.register(Ingestor) diff --git a/peachjam/migrations/0002_casenumber_judge_judgment_judgmentmediasummaryfile_mattertype.py b/peachjam/migrations/0002_casenumber_judge_judgment_judgmentmediasummaryfile_mattertype.py index 4cc7c176d..975699d6a 100644 --- a/peachjam/migrations/0002_casenumber_judge_judgment_judgmentmediasummaryfile_mattertype.py +++ b/peachjam/migrations/0002_casenumber_judge_judgment_judgmentmediasummaryfile_mattertype.py @@ -58,7 +58,6 @@ class Migration(migrations.Migration): to="peachjam.author", ), ), - ("judges", models.ManyToManyField(blank=True, to="peachjam.Judge")), ], options={ "ordering": ["title"], @@ -154,4 +153,47 @@ class Migration(migrations.Migration): ), ], ), + migrations.CreateModel( + name="Bench", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "judge", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="peachjam.judge", + verbose_name="judge", + ), + ), + ( + "judgment", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="bench", + to="peachjam.judgment", + verbose_name="judgment", + ), + ), + ], + options={ + "db_table": "peachjam_judgment_judges", + "ordering": ("pk",), + "unique_together": {("judgment", "judge")}, + }, + ), + migrations.AddField( + model_name="judgment", + name="judges", + field=models.ManyToManyField( + through="peachjam.Bench", to="peachjam.Judge", verbose_name="judges" + ), + ), ] diff --git a/peachjam/migrations/0042_i18n_models.py b/peachjam/migrations/0042_i18n_models.py index 44e9baaf9..efdfc53c0 100644 --- a/peachjam/migrations/0042_i18n_models.py +++ b/peachjam/migrations/0042_i18n_models.py @@ -879,7 +879,10 @@ class Migration(migrations.Migration): model_name="judgment", name="judges", field=models.ManyToManyField( - blank=True, to="peachjam.Judge", verbose_name="judges" + blank=True, + through="peachjam.Bench", + to="peachjam.Judge", + verbose_name="judges", ), ), migrations.AlterField( diff --git a/peachjam/migrations/0092_alter_judge_options.py b/peachjam/migrations/0092_alter_judge_options.py new file mode 100644 index 000000000..827fd6f7c --- /dev/null +++ b/peachjam/migrations/0092_alter_judge_options.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.16 on 2023-07-21 08:51 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("peachjam", "0091_peachjamsettings_mailchimp_form_url"), + ] + + operations = [ + migrations.AlterModelOptions( + name="judge", + options={ + "ordering": ("name",), + "verbose_name": "judge", + "verbose_name_plural": "judges", + }, + ), + ] diff --git a/peachjam/models/judgment.py b/peachjam/models/judgment.py index c2d1d6b9a..6d5552c3b 100644 --- a/peachjam/models/judgment.py +++ b/peachjam/models/judgment.py @@ -30,10 +30,7 @@ class Judge(models.Model): description = models.TextField(_("description"), blank=True) class Meta: - ordering = ( - "pk", - "name", - ) + ordering = ("name",) verbose_name = _("judge") verbose_name_plural = _("judges") @@ -140,6 +137,29 @@ def save(self, *args, **kwargs): return super().save(*args, **kwargs) +class Bench(models.Model): + # This model is not strictly necessary, as it's almost identical to the default that Django creates + # for a many-to-many relationship. However, by creating it, we can indicate that the ordering should + # be on the PK of the model. This means that we can preserve the ordering of Judges as the are + # entered in the admin interface. + # + # To use this effectively, views that need the judges to be ordered, should call "judgement.bench.all()" + # and not "judgment.judges.all()". + judgment = models.ForeignKey( + "Judgment", + related_name="bench", + on_delete=models.CASCADE, + verbose_name=_("judgment"), + ) + judge = models.ForeignKey(Judge, on_delete=models.PROTECT, verbose_name=_("judge")) + + class Meta: + # this is to re-use the existing table rather than creating a new one + db_table = "peachjam_judgment_judges" + ordering = ("pk",) + unique_together = ("judgment", "judge") + + class Judgment(CoreDocument): court = models.ForeignKey( Court, on_delete=models.PROTECT, null=True, verbose_name=_("court") @@ -151,7 +171,9 @@ class Judgment(CoreDocument): related_name="judgments", blank=True, ) - judges = models.ManyToManyField(Judge, blank=True, verbose_name=_("judges")) + judges = models.ManyToManyField( + Judge, blank=True, verbose_name=_("judges"), through=Bench + ) attorneys = models.ManyToManyField( Attorney, blank=True, verbose_name=_("attorneys") ) diff --git a/peachjam/templates/peachjam/layouts/document_detail.html b/peachjam/templates/peachjam/layouts/document_detail.html index fd161e1cc..f7cf27fe6 100644 --- a/peachjam/templates/peachjam/layouts/document_detail.html +++ b/peachjam/templates/peachjam/layouts/document_detail.html @@ -205,14 +205,14 @@

{{ document.title }}

{% endif %} {% endwith %} - {% with document.judges.all as judges %} + {% with document.bench.all as judges %} {% if judges %}
{% trans 'Judges' %}
- {% for judge in judges %} - {{ judge.name }} + {% for bench in judges %} + {{ bench.judge.name }} {% if not forloop.last %},{% endif %} {% endfor %}