From e7cfdaae36d72bce28c5e4fea6a5dd7f514822c6 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 7 Feb 2025 14:54:12 +0100 Subject: [PATCH 01/19] personal: Set more natural default order --- mpicms/personal/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 27d77ca..7b1c853 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -78,6 +78,9 @@ class Position(models.Model): def __str__(self): return self.title + class Meta: + ordering = ["title"] + class Status(models.Model): title = models.CharField(_("status"), max_length=50) @@ -91,6 +94,7 @@ def __str__(self): class Meta: verbose_name_plural = "status" + ordering = ["title"] class SpecialFunction(models.Model): @@ -103,6 +107,8 @@ class SpecialFunction(models.Model): def __str__(self): return self.title + class Meta: + ordering = ["title"] @register_snippet class Contact(index.Indexed, ClusterableModel): @@ -211,7 +217,7 @@ def __str__(self): class Meta: # noqa verbose_name = 'Group' verbose_name_plural = 'Groups' - ordering = ['-priority'] + ordering = ['name'] class WrittenConsent(models.Model): From f1c94060bf6da52df42b0ee0ae12655692155ce0 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sat, 8 Feb 2025 19:23:10 +0100 Subject: [PATCH 02/19] personal: Remove Group.members method In 50dd4a655704c9a615892ce96ad755d48cac2d07 ("contactlist: Add selector for Position and Special Function") we remove the only user of this method. Remove dead code. --- mpicms/personal/models.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 7b1c853..ae9d258 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -207,10 +207,6 @@ class Group(index.Indexed, ClusterableModel): index.SearchField('slug'), ] - @property - def members(self): - return [relation.contact for relation in self.contacts.select_related('contact')] - def __str__(self): return self.name or self.slug From 5c01a7ff1128c6cda0b520e2c6717e5a9e252c2d Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sat, 8 Feb 2025 19:47:27 +0100 Subject: [PATCH 03/19] personal: Fix Contact admin table head Fix table header for groups Fixes ef3b68f1e27e7be91a37a611a2d33bd1781489ac ("Multiple positions per contact") --- mpicms/personal/wagtail_hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpicms/personal/wagtail_hooks.py b/mpicms/personal/wagtail_hooks.py index 225e7d0..c25fb9c 100644 --- a/mpicms/personal/wagtail_hooks.py +++ b/mpicms/personal/wagtail_hooks.py @@ -54,7 +54,7 @@ def get_groups(self, obj): def get_positions(self, obj): return ", ".join([position.__str__() for position in Position.objects.filter(contacts__in=obj.positions.all()).distinct()]) - get_groups.short_description = _('Positions') + get_positions.short_description = _('Positions') def get_queryset(self, request): qs = self.model._default_manager.include_inactive() From 578096e89d5a3e13a0466521ff6cf650d8c12a6e Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sat, 8 Feb 2025 20:07:22 +0100 Subject: [PATCH 04/19] Make migrations Create migrations with ./manage.py makemigrations Note, that the new migration doesn't actually change the database scheme: buczek@theinternet:~/git/mpicms (progress)$ ./manage.py sqlmigrate personal 0028 DEBUG 2025-02-08 20:08:42,206 asyncio Using selector: EpollSelector BEGIN; -- -- Change Meta options on group -- -- -- Change Meta options on position -- -- -- Change Meta options on specialfunction -- -- -- Change Meta options on status -- COMMIT; --- .../migrations/0028_auto_20250208_2003.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 mpicms/personal/migrations/0028_auto_20250208_2003.py diff --git a/mpicms/personal/migrations/0028_auto_20250208_2003.py b/mpicms/personal/migrations/0028_auto_20250208_2003.py new file mode 100644 index 0000000..e5a6461 --- /dev/null +++ b/mpicms/personal/migrations/0028_auto_20250208_2003.py @@ -0,0 +1,29 @@ +# Generated by Django 3.1.7 on 2025-02-08 19:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0027_auto_20250115_1509'), + ] + + operations = [ + migrations.AlterModelOptions( + name='group', + options={'ordering': ['name'], 'verbose_name': 'Group', 'verbose_name_plural': 'Groups'}, + ), + migrations.AlterModelOptions( + name='position', + options={'ordering': ['title']}, + ), + migrations.AlterModelOptions( + name='specialfunction', + options={'ordering': ['title']}, + ), + migrations.AlterModelOptions( + name='status', + options={'ordering': ['title'], 'verbose_name_plural': 'status'}, + ), + ] From f43cb59b280393d6846b1b48f953780d812b34e5 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sat, 8 Feb 2025 20:49:04 +0100 Subject: [PATCH 05/19] personal: Change positions to ManyToManyField We want to split responsibilities for defining positions and assigning contacts to position. Therefore we no longer want the positions inline panel in the contact model admin. Make positions into a simple ManyToMany field. Add sql code to autogenerated migration to transfer data from the old through table "personal_contactpositions" to the new one ("personal_contact_positions"). Adapt queries. --- .../migrations/0029_auto_20250209_1010.py | 22 ++++++++++++++++ mpicms/personal/models.py | 25 ++----------------- mpicms/personal/views.py | 2 +- mpicms/personal/wagtail_hooks.py | 5 ++-- mpicms/templates/personal/list.html | 2 +- 5 files changed, 28 insertions(+), 28 deletions(-) create mode 100644 mpicms/personal/migrations/0029_auto_20250209_1010.py diff --git a/mpicms/personal/migrations/0029_auto_20250209_1010.py b/mpicms/personal/migrations/0029_auto_20250209_1010.py new file mode 100644 index 0000000..944728e --- /dev/null +++ b/mpicms/personal/migrations/0029_auto_20250209_1010.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.7 on 2025-02-09 09:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0028_auto_20250208_2003'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='positions', + field=models.ManyToManyField(blank=True, related_name='contacts', to='personal.Position', verbose_name='positions'), + ), + migrations.RunSQL("INSERT INTO personal_contact_positions(id, contact_id, position_id) SELECT id, contact_id, position_id FROM personal_contactpositions"), + migrations.DeleteModel( + name='ContactPositions', + ), + ] diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index ae9d258..22cbf63 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -36,25 +36,6 @@ class ContactGroups(Orderable, models.Model): ] -class ContactPositions(Orderable, models.Model): - """ - This defines the relationship between the `Position` within the `Contact` model below. - """ - contact = FilterableParentalKey( - 'Contact', related_name=_('positions'), on_delete=models.CASCADE - ) - position = models.ForeignKey( - 'personal.Position', - related_name='contacts', - on_delete=models.CASCADE, - verbose_name=_('position') - ) - - panels = [ - SnippetChooserPanel('position'), - ] - - class ContactManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(is_active=True) @@ -136,6 +117,7 @@ class Contact(index.Indexed, ClusterableModel): help_text=_("Priority from 0-999 to determine the sorting order.")) status = models.ForeignKey(Status, on_delete=models.SET_NULL, blank=True, null=True) special_functions = models.ManyToManyField(SpecialFunction, verbose_name=_('special functions'), blank=True) + positions = models.ManyToManyField(Position, related_name="contacts", blank=True, verbose_name=_('positions')) objects = ContactManager() @@ -147,10 +129,7 @@ class Contact(index.Indexed, ClusterableModel): FieldPanel('academic_suffix'), ], heading='Name'), FieldPanel('status'), - InlinePanel( - 'positions', label="Positions", - panels=None - ), + FieldPanel('positions'), FieldPanel('special_functions'), FieldPanel('email'), FieldPanel('phone'), diff --git a/mpicms/personal/views.py b/mpicms/personal/views.py index 8ccea1e..7306283 100644 --- a/mpicms/personal/views.py +++ b/mpicms/personal/views.py @@ -16,7 +16,7 @@ def get_queryset(self): qs = qs.filter(groups__group_id=group_pk) if position_pk is not None and position_pk != "": - qs = qs.filter(positions__position_id=position_pk) + qs = qs.filter(positions=position_pk) if special_function_pk is not None and special_function_pk != "": qs = qs.filter(special_functions=special_function_pk) diff --git a/mpicms/personal/wagtail_hooks.py b/mpicms/personal/wagtail_hooks.py index c25fb9c..5be9f1a 100644 --- a/mpicms/personal/wagtail_hooks.py +++ b/mpicms/personal/wagtail_hooks.py @@ -40,7 +40,7 @@ class ContactAdmin(ModelAdmin): menu_label = _('Persons') menu_icon = 'user' list_display = ['title', 'first_name', 'last_name', 'get_positions', 'email', 'phone', 'room', 'get_groups'] - list_filter = ['groups__group', 'is_active', 'positions__position'] + list_filter = ['groups__group', 'is_active', 'positions'] search_fields = ['title', 'first_name', 'last_name', 'email', 'phone', 'room'] edit_view_class = ContactEditView @@ -52,8 +52,7 @@ def get_groups(self, obj): get_groups.short_description = _('Groups') def get_positions(self, obj): - return ", ".join([position.__str__() for position in - Position.objects.filter(contacts__in=obj.positions.all()).distinct()]) + return ", ".join([position.__str__() for position in obj.positions.all()]) get_positions.short_description = _('Positions') def get_queryset(self, request): diff --git a/mpicms/templates/personal/list.html b/mpicms/templates/personal/list.html index 0cab0cf..5b691db 100644 --- a/mpicms/templates/personal/list.html +++ b/mpicms/templates/personal/list.html @@ -110,7 +110,7 @@

{% trans 'Contact List' %}

{{ contact.phone }} {{ contact.room | add_room_links }} {% for contactgroup in contact.groups.all %}{{ contactgroup.group }}
{% endfor %} - {% for contactposition in contact.positions.all %}{{ contactposition.position }}
{% endfor %} + {% for position in contact.positions.all %}{{ position }}
{% endfor %} {% for specialfunction in contact.special_functions.all %}{{ specialfunction.title }}
{% endfor %} {% endfor %} From 108adbbafca33d8b02dc4d447f324dd243ff0969 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 10:47:40 +0100 Subject: [PATCH 06/19] personal: Move Group class definition before Contact We want to reference Group from Contact in the following commit, so move the class in the source file. --- mpicms/personal/models.py | 55 ++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 22cbf63..d43cab3 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -91,6 +91,34 @@ def __str__(self): class Meta: ordering = ["title"] + +@register_snippet +class Group(index.Indexed, ClusterableModel): + slug = models.CharField(_("slug"), max_length=254) + name = models.CharField(_("name"), max_length=254, blank=True) + priority = models.PositiveSmallIntegerField( + _("priority"), blank=True, default=0, validators=[MaxValueValidator(99)], + help_text=_("Priority from 0-99 to determine the sorting order.")) + + panels = [ + FieldPanel('name'), + FieldPanel('priority'), + ] + + search_fields = [ + index.SearchField('name', partial_match=True), + index.SearchField('slug'), + ] + + def __str__(self): + return self.name or self.slug + + class Meta: # noqa + verbose_name = 'Group' + verbose_name_plural = 'Groups' + ordering = ['name'] + + @register_snippet class Contact(index.Indexed, ClusterableModel): """ @@ -168,33 +196,6 @@ class Meta: # noqa ordering = ['last_name'] -@register_snippet -class Group(index.Indexed, ClusterableModel): - slug = models.CharField(_("slug"), max_length=254) - name = models.CharField(_("name"), max_length=254, blank=True) - priority = models.PositiveSmallIntegerField( - _("priority"), blank=True, default=0, validators=[MaxValueValidator(99)], - help_text=_("Priority from 0-99 to determine the sorting order.")) - - panels = [ - FieldPanel('name'), - FieldPanel('priority'), - ] - - search_fields = [ - index.SearchField('name', partial_match=True), - index.SearchField('slug'), - ] - - def __str__(self): - return self.name or self.slug - - class Meta: # noqa - verbose_name = 'Group' - verbose_name_plural = 'Groups' - ordering = ['name'] - - class WrittenConsent(models.Model): ref = models.CharField("ID", max_length=10, unique=True) comment = models.TextField("comment", blank=True) From 14a1c7926c50c822f7e207017c0f6d0228926b95 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 12:23:56 +0100 Subject: [PATCH 07/19] personal: Change groups to ManyToManyField We want to split responsibilities for defining groups and assigning groups to position. Therefore we no longer want thegroupspositions inline panel in the contact model admin. Make groups into a simple ManyToMany field. Add sql code to autogenerated migration to transfer data from the old through table "personal_contactgroups" to the new one ("personal_contact_groups"). Adapt queries. --- .../migrations/0030_auto_20250209_1143.py | 22 ++++++++++++++++ mpicms/personal/models.py | 25 +++---------------- mpicms/personal/views.py | 2 +- mpicms/personal/wagtail_hooks.py | 4 +-- mpicms/templates/personal/list.html | 2 +- 5 files changed, 29 insertions(+), 26 deletions(-) create mode 100644 mpicms/personal/migrations/0030_auto_20250209_1143.py diff --git a/mpicms/personal/migrations/0030_auto_20250209_1143.py b/mpicms/personal/migrations/0030_auto_20250209_1143.py new file mode 100644 index 0000000..85f6c1a --- /dev/null +++ b/mpicms/personal/migrations/0030_auto_20250209_1143.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.7 on 2025-02-09 10:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0029_auto_20250209_1010'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='groups', + field=models.ManyToManyField(blank=True, related_name='contacts', to='personal.Group', verbose_name='groups'), + ), + migrations.RunSQL("INSERT INTO personal_contact_groups(id, contact_id, group_id) SELECT id, contact_id, group_id FROM personal_contactgroups"), + migrations.DeleteModel( + name='ContactGroups', + ), + ] diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index d43cab3..1875852 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -12,30 +12,12 @@ from modelcluster.fields import ParentalKey +# still used in migrations class FilterableParentalKey(ParentalKey): def get_related_field(self): return self.remote_field -class ContactGroups(Orderable, models.Model): - """ - This defines the relationship between the `Group` within the `Contact` model below. - """ - contact = FilterableParentalKey( - 'Contact', related_name=_('groups'), on_delete=models.CASCADE - ) - group = models.ForeignKey( - 'personal.Group', - related_name='contacts', - on_delete=models.CASCADE, - verbose_name=_('group') - ) - - panels = [ - SnippetChooserPanel('group'), - ] - - class ContactManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(is_active=True) @@ -146,6 +128,7 @@ class Contact(index.Indexed, ClusterableModel): status = models.ForeignKey(Status, on_delete=models.SET_NULL, blank=True, null=True) special_functions = models.ManyToManyField(SpecialFunction, verbose_name=_('special functions'), blank=True) positions = models.ManyToManyField(Position, related_name="contacts", blank=True, verbose_name=_('positions')) + groups = models.ManyToManyField(Group, related_name="contacts", blank=True, verbose_name=_('groups')) objects = ContactManager() @@ -157,14 +140,12 @@ class Contact(index.Indexed, ClusterableModel): FieldPanel('academic_suffix'), ], heading='Name'), FieldPanel('status'), + FieldPanel('groups'), FieldPanel('positions'), FieldPanel('special_functions'), FieldPanel('email'), FieldPanel('phone'), FieldPanel('room'), - InlinePanel( - 'groups', label="Groups", - panels=None), FieldPanel('is_active'), FieldPanel('priority'), ] diff --git a/mpicms/personal/views.py b/mpicms/personal/views.py index 7306283..7f198da 100644 --- a/mpicms/personal/views.py +++ b/mpicms/personal/views.py @@ -13,7 +13,7 @@ def get_queryset(self): special_function_pk = self.request.GET.get('special_function') qs = super().get_queryset(); if group_pk is not None and group_pk != "": - qs = qs.filter(groups__group_id=group_pk) + qs = qs.filter(groups=group_pk) if position_pk is not None and position_pk != "": qs = qs.filter(positions=position_pk) diff --git a/mpicms/personal/wagtail_hooks.py b/mpicms/personal/wagtail_hooks.py index 5be9f1a..59df651 100644 --- a/mpicms/personal/wagtail_hooks.py +++ b/mpicms/personal/wagtail_hooks.py @@ -40,7 +40,7 @@ class ContactAdmin(ModelAdmin): menu_label = _('Persons') menu_icon = 'user' list_display = ['title', 'first_name', 'last_name', 'get_positions', 'email', 'phone', 'room', 'get_groups'] - list_filter = ['groups__group', 'is_active', 'positions'] + list_filter = ['groups', 'is_active', 'positions'] search_fields = ['title', 'first_name', 'last_name', 'email', 'phone', 'room'] edit_view_class = ContactEditView @@ -48,7 +48,7 @@ class ContactAdmin(ModelAdmin): delete_view_class = ContactDeleteView def get_groups(self, obj): - return ", ".join([group.__str__() for group in Group.objects.filter(contacts__in=obj.groups.all()).distinct()]) + return ", ".join([group.__str__() for group in obj.groups.all()]) get_groups.short_description = _('Groups') def get_positions(self, obj): diff --git a/mpicms/templates/personal/list.html b/mpicms/templates/personal/list.html index 5b691db..9df0ad9 100644 --- a/mpicms/templates/personal/list.html +++ b/mpicms/templates/personal/list.html @@ -109,7 +109,7 @@

{% trans 'Contact List' %}

{{ contact.email }} {{ contact.phone }} {{ contact.room | add_room_links }} - {% for contactgroup in contact.groups.all %}{{ contactgroup.group }}
{% endfor %} + {% for group in contact.groups.all %}{{ group }}
{% endfor %} {% for position in contact.positions.all %}{{ position }}
{% endfor %} {% for specialfunction in contact.special_functions.all %}{{ specialfunction.title }}
{% endfor %} From 4eaae098c7ee613fcfd63910a1cece5777b30af2 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 13:14:46 +0100 Subject: [PATCH 08/19] personal: Downgrade from ClusterableModel to Model We no longer need modelcluster for Groups and Contact, as they are edited seperately. Downgrade base class from modelcluster.models.ClusterableModel to django.db.models.Model --- mpicms/personal/models.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 1875852..66279fe 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -8,7 +8,6 @@ from wagtail.search import index from wagtail.snippets.edit_handlers import SnippetChooserPanel -from modelcluster.models import ClusterableModel from modelcluster.fields import ParentalKey @@ -75,7 +74,7 @@ class Meta: @register_snippet -class Group(index.Indexed, ClusterableModel): +class Group(index.Indexed, models.Model): slug = models.CharField(_("slug"), max_length=254) name = models.CharField(_("name"), max_length=254, blank=True) priority = models.PositiveSmallIntegerField( @@ -102,18 +101,7 @@ class Meta: # noqa @register_snippet -class Contact(index.Indexed, ClusterableModel): - """ - A Django model to store People objects. - It uses the `@register_snippet` decorator to allow it to be accessible - via the Snippets UI (e.g. /admin/snippets/base/people/) - `People` uses the `ClusterableModel`, which allows the relationship with - another model to be stored locally to the 'parent' model (e.g. a PageModel) - until the parent is explicitly saved. This allows the editor to use the - 'Preview' button, to preview the content, without saving the relationships - to the database. - https://github.com/wagtail/django-modelcluster - """ +class Contact(index.Indexed, models.Model): title = models.CharField(_("title"), max_length=15, blank=True) first_name = models.CharField(_("first name"), max_length=50, blank=True) last_name = models.CharField(_("last name"), max_length=50, blank=True) From 2fbd0520fbd195f18fe8ab44eeca272df57d4c39 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 13:23:24 +0100 Subject: [PATCH 09/19] personal.models: Remove unused imports --- mpicms/personal/models.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 66279fe..af4f613 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -2,11 +2,9 @@ from django.utils.translation import gettext_lazy as _ from django.core.validators import MaxValueValidator -from wagtail.core.models import Orderable -from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel +from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel from wagtail.snippets.models import register_snippet from wagtail.search import index -from wagtail.snippets.edit_handlers import SnippetChooserPanel from modelcluster.fields import ParentalKey From 6a957c5ad80530a6ddc966d3f7ff0361dd7b9116 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 13:31:08 +0100 Subject: [PATCH 10/19] personal.views: Remove unnecessary semicolon Fixes 50dd4a655704c9a615892ce96ad755d48cac2d07 ("contactlist: Add selector for Position and Special Function") --- mpicms/personal/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpicms/personal/views.py b/mpicms/personal/views.py index 7f198da..312ad8c 100644 --- a/mpicms/personal/views.py +++ b/mpicms/personal/views.py @@ -11,7 +11,7 @@ def get_queryset(self): group_pk = self.request.GET.get('group') position_pk = self.request.GET.get('position') special_function_pk = self.request.GET.get('special_function') - qs = super().get_queryset(); + qs = super().get_queryset() if group_pk is not None and group_pk != "": qs = qs.filter(groups=group_pk) From ac2eca9ccc7ceeb4d5f240de9a11714c4d5d4d41 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 13:39:55 +0100 Subject: [PATCH 11/19] personal: Remove field slug from Group --- mpicms/personal/models.py | 4 +--- mpicms/personal/wagtail_hooks.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index af4f613..5866f93 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -73,7 +73,6 @@ class Meta: @register_snippet class Group(index.Indexed, models.Model): - slug = models.CharField(_("slug"), max_length=254) name = models.CharField(_("name"), max_length=254, blank=True) priority = models.PositiveSmallIntegerField( _("priority"), blank=True, default=0, validators=[MaxValueValidator(99)], @@ -86,11 +85,10 @@ class Group(index.Indexed, models.Model): search_fields = [ index.SearchField('name', partial_match=True), - index.SearchField('slug'), ] def __str__(self): - return self.name or self.slug + return self.name class Meta: # noqa verbose_name = 'Group' diff --git a/mpicms/personal/wagtail_hooks.py b/mpicms/personal/wagtail_hooks.py index 59df651..cbce611 100644 --- a/mpicms/personal/wagtail_hooks.py +++ b/mpicms/personal/wagtail_hooks.py @@ -67,7 +67,7 @@ class GroupAdmin(ModelAdmin): model = Group menu_label = _('Groups') menu_icon = 'group' - search_fields = ['name', 'slug'] + search_fields = ['name'] class PositionAdmin(ModelAdmin): From 768a10b5689f19be851159db29f76ab83854a1b8 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 13:42:49 +0100 Subject: [PATCH 12/19] personal: Remove field priority from Group and Contact --- mpicms/personal/models.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 5866f93..93aee8a 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -74,13 +74,9 @@ class Meta: @register_snippet class Group(index.Indexed, models.Model): name = models.CharField(_("name"), max_length=254, blank=True) - priority = models.PositiveSmallIntegerField( - _("priority"), blank=True, default=0, validators=[MaxValueValidator(99)], - help_text=_("Priority from 0-99 to determine the sorting order.")) panels = [ FieldPanel('name'), - FieldPanel('priority'), ] search_fields = [ @@ -106,9 +102,6 @@ class Contact(index.Indexed, models.Model): phone = models.CharField(_("phone number"), blank=True, max_length=50) room = models.CharField(_("room"), max_length=50, blank=True) is_active = models.BooleanField(_("is active"), default=True) - priority = models.PositiveSmallIntegerField( - _("priority"), blank=True, default=0, validators=[MaxValueValidator(999)], - help_text=_("Priority from 0-999 to determine the sorting order.")) status = models.ForeignKey(Status, on_delete=models.SET_NULL, blank=True, null=True) special_functions = models.ManyToManyField(SpecialFunction, verbose_name=_('special functions'), blank=True) positions = models.ManyToManyField(Position, related_name="contacts", blank=True, verbose_name=_('positions')) @@ -131,7 +124,6 @@ class Contact(index.Indexed, models.Model): FieldPanel('phone'), FieldPanel('room'), FieldPanel('is_active'), - FieldPanel('priority'), ] search_fields = [ @@ -157,7 +149,6 @@ def __str__(self): class Meta: # noqa verbose_name = 'Contact' verbose_name_plural = 'Contacts' - # ordering = ['groups__group', '-priority', 'last_name'] ordering = ['last_name'] From de599d8fda93dbceb5c69bbe4e6bafa3edf7c411 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 13:58:36 +0100 Subject: [PATCH 13/19] Make migrations --- .../migrations/0031_auto_20250209_1358.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 mpicms/personal/migrations/0031_auto_20250209_1358.py diff --git a/mpicms/personal/migrations/0031_auto_20250209_1358.py b/mpicms/personal/migrations/0031_auto_20250209_1358.py new file mode 100644 index 0000000..a5093d6 --- /dev/null +++ b/mpicms/personal/migrations/0031_auto_20250209_1358.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.7 on 2025-02-09 12:58 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0030_auto_20250209_1143'), + ] + + operations = [ + migrations.RemoveField( + model_name='contact', + name='priority', + ), + migrations.RemoveField( + model_name='group', + name='priority', + ), + migrations.RemoveField( + model_name='group', + name='slug', + ), + ] From 3142661a227bc9a32724662d52b3bd02d209c678 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 13:55:08 +0100 Subject: [PATCH 14/19] personal: Rearrange Contact Model Admin Use FieldsPanels inside a single MutiFieldPanel, because this is a bit compacter. Rearrange order. Intentionally skip "status" for now as the usage is not yet clear and no choices are defined. --- mpicms/personal/models.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 93aee8a..e3fed00 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -115,15 +115,14 @@ class Contact(index.Indexed, models.Model): FieldPanel('first_name'), FieldPanel('last_name'), FieldPanel('academic_suffix'), - ], heading='Name'), - FieldPanel('status'), - FieldPanel('groups'), - FieldPanel('positions'), - FieldPanel('special_functions'), - FieldPanel('email'), - FieldPanel('phone'), - FieldPanel('room'), - FieldPanel('is_active'), + FieldPanel('is_active'), + FieldPanel('email'), + FieldPanel('phone'), + FieldPanel('room'), + FieldPanel('groups'), + FieldPanel('positions'), + FieldPanel('special_functions'), + ]), ] search_fields = [ From 0a502c0a53c0edf3b03031a28ff69e9fceb783f1 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 14:03:59 +0100 Subject: [PATCH 15/19] personal: Remove @register_snppet decorator From Position, Group Only Contact is used as snippet, but not Positon or Group, so remove the @register_snippet decorator. --- mpicms/personal/models.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index e3fed00..3cced41 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -23,7 +23,6 @@ def include_inactive(self): return super().get_queryset() -@register_snippet class Position(models.Model): title = models.CharField(_("title"), max_length=50) @@ -71,7 +70,6 @@ class Meta: ordering = ["title"] -@register_snippet class Group(index.Indexed, models.Model): name = models.CharField(_("name"), max_length=254, blank=True) From 148f1038f17ee4a4ed12a7c8b440da81592da887 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 14:54:15 +0100 Subject: [PATCH 16/19] personal: Add Contact string represeantation Change default string representation from "Dr. Henry Jeckyl" to "Jekyll, Henry". Add property method "name" to return the same representation. Add property name_and_title to return name with title(s) included ("Jekyll, Dr. Henry, PhD MD") --- mpicms/personal/models.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mpicms/personal/models.py b/mpicms/personal/models.py index 3cced41..c42e213 100644 --- a/mpicms/personal/models.py +++ b/mpicms/personal/models.py @@ -136,9 +136,21 @@ class Contact(index.Indexed, models.Model): # index.SearchField('groups'), ] + @property + def name(self): + return ", ".join(filter(None, (self.last_name, self.first_name))) + + @property + def name_and_title(self): + return ", ".join(filter(None, ( + self.last_name, + " ".join(filter(None, (self.title, self.first_name))), + self.academic_suffix, + ))) + def __str__(self): if self.first_name or self.last_name: - return " ".join(filter(None, (self.title, self.first_name, self.last_name))) + return ", ".join(filter(None, (self.last_name, self.first_name))) else: return self.email From 9b17dc68cc47d0b903ea5f2e7267af83c000d437 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 9 Feb 2025 15:02:36 +0100 Subject: [PATCH 17/19] contactlist: Use name_and_title Save vertical space by combining names and titles into one column. --- mpicms/templates/personal/list.html | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mpicms/templates/personal/list.html b/mpicms/templates/personal/list.html index 9df0ad9..0cac3dd 100644 --- a/mpicms/templates/personal/list.html +++ b/mpicms/templates/personal/list.html @@ -89,9 +89,7 @@

{% trans 'Contact List' %}

- - - + @@ -103,9 +101,7 @@

{% trans 'Contact List' %}

{% for contact in object_list %} - - - + @@ -120,7 +116,7 @@

{% trans 'Contact List' %}

{% trans 'Title' %}{% trans 'First Name' %}{% trans 'Last Name' %}{% trans 'Name' %} {% trans 'Email' %} {% trans 'Phone' %} {% trans 'Room' %}
{{ contact.title }}{{ contact.first_name }}{{ contact.last_name }}{{ contact.name_and_title }} {{ contact.phone }} {{ contact.room | add_room_links }}