feat: group people by role priority

This commit is contained in:
mohamad
2026-10-29 03:53:39 +08:00
parent 7c186b4230
commit 641f4e6cee
15 changed files with 186 additions and 45 deletions
@@ -0,0 +1,55 @@
# Generated by Django 5.2.16 on 2026-10-28 19:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('products', '0025_articleperson_mainproductperson_subproductperson'),
]
operations = [
migrations.AlterModelOptions(
name='articleperson',
options={'ordering': [models.Case(models.When(role__iexact='lead', then=models.Value(0)), models.When(role__iexact='leader', then=models.Value(0)), models.When(role__iexact='organizer', then=models.Value(1)), models.When(role__iexact='collaborator', then=models.Value(2)), default=models.Value(3), output_field=models.IntegerField()), 'order', 'pk'], 'verbose_name': 'Project article person', 'verbose_name_plural': 'Project article people'},
),
migrations.AlterModelOptions(
name='mainproductperson',
options={'ordering': [models.Case(models.When(role__iexact='lead', then=models.Value(0)), models.When(role__iexact='leader', then=models.Value(0)), models.When(role__iexact='organizer', then=models.Value(1)), models.When(role__iexact='collaborator', then=models.Value(2)), default=models.Value(3), output_field=models.IntegerField()), 'order', 'pk'], 'verbose_name': 'Main project person', 'verbose_name_plural': 'Main project people'},
),
migrations.AlterModelOptions(
name='subproductperson',
options={'ordering': [models.Case(models.When(role__iexact='lead', then=models.Value(0)), models.When(role__iexact='leader', then=models.Value(0)), models.When(role__iexact='organizer', then=models.Value(1)), models.When(role__iexact='collaborator', then=models.Value(2)), default=models.Value(3), output_field=models.IntegerField()), 'order', 'pk'], 'verbose_name': 'Sub-project person', 'verbose_name_plural': 'Sub-project people'},
),
migrations.AlterField(
model_name='articleperson',
name='order',
field=models.PositiveIntegerField(default=0, help_text='Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.', verbose_name='Display order'),
),
migrations.AlterField(
model_name='articleperson',
name='role',
field=models.CharField(default='Collaborator', help_text='Type Lead, Leader, Organizer, Collaborator, or any other role name.', max_length=100, verbose_name='Role / group'),
),
migrations.AlterField(
model_name='mainproductperson',
name='order',
field=models.PositiveIntegerField(default=0, help_text='Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.', verbose_name='Display order'),
),
migrations.AlterField(
model_name='mainproductperson',
name='role',
field=models.CharField(default='Collaborator', help_text='Type Lead, Leader, Organizer, Collaborator, or any other role name.', max_length=100, verbose_name='Role / group'),
),
migrations.AlterField(
model_name='subproductperson',
name='order',
field=models.PositiveIntegerField(default=0, help_text='Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.', verbose_name='Display order'),
),
migrations.AlterField(
model_name='subproductperson',
name='role',
field=models.CharField(default='Collaborator', help_text='Type Lead, Leader, Organizer, Collaborator, or any other role name.', max_length=100, verbose_name='Role / group'),
),
]
+8 -6
View File
@@ -227,7 +227,7 @@ class Article(models.Model):
class ProjectPerson(models.Model):
role = models.CharField(
"Role / group", max_length=100, default="Collaborator",
help_text="Type Organizer, Collaborator, or any other role name.",
help_text="Type Lead, Leader, Organizer, Collaborator, or any other role name.",
)
name = models.CharField(max_length=200)
description = models.TextField(blank=True)
@@ -239,23 +239,25 @@ class ProjectPerson(models.Model):
url = models.URLField(blank=True)
order = models.PositiveIntegerField(
"Display order", default=0,
help_text="Smaller numbers appear first. Organizers appear before collaborators, then custom roles.",
help_text="Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.",
)
class Meta:
abstract = True
ordering = [
models.Case(
models.When(role__iexact="organizer", then=models.Value(0)),
models.When(role__iexact="collaborator", then=models.Value(1)),
default=models.Value(2), output_field=models.IntegerField(),
models.When(role__iexact="lead", then=models.Value(0)),
models.When(role__iexact="leader", then=models.Value(0)),
models.When(role__iexact="organizer", then=models.Value(1)),
models.When(role__iexact="collaborator", then=models.Value(2)),
default=models.Value(3), output_field=models.IntegerField(),
),
"order", "pk",
]
@property
def role_label(self):
return self.role.title() if self.role.casefold() in {"organizer", "collaborator"} else self.role
return self.role.title() if self.role.casefold() in {"lead", "leader", "organizer", "collaborator"} else self.role
def __str__(self):
return f"{self.name} ({self.role_label})"
+6
View File
@@ -62,11 +62,17 @@ class MainProductDetailViewTest(ProductViewsSetup):
def test_project_and_article_people_are_independent_and_ordered(self):
MainProductPerson.objects.create(main_product=self.main_product, name="Main collaborator", role="Collaborator", order=1)
MainProductPerson.objects.create(main_product=self.main_product, name="Main organizer", role="Organizer", order=9)
MainProductPerson.objects.create(main_product=self.main_product, name="Main leader", role="Leader", order=2)
MainProductPerson.objects.create(main_product=self.main_product, name="Main lead", role="Lead", order=1)
main_article = Article.objects.create(main_product=self.main_product, title="Main article", description="Text")
ArticlePerson.objects.create(article=main_article, name="Article advisor", role="Scientific advisor", order=0)
response = self.client.get(self.main_product.get_absolute_url())
html = response.content.decode()
self.assertLess(html.index("Main lead"), html.index("Main leader"))
self.assertLess(html.index("Main leader"), html.index("Main organizer"))
self.assertLess(html.index("Main organizer"), html.index("Main collaborator"))
self.assertLess(html.index("Lead / Leader"), html.index(">Organizers</h3>"))
self.assertLess(html.index(">Organizers</h3>"), html.index(">Collaborators</h3>"))
self.assertContains(response, "Article advisor")
self.assertNotContains(response, "Sub collaborator")
self.assertContains(response, f'id="article-{main_article.pk}-people"')