diff --git a/scipost_django/affiliates/forms.py b/scipost_django/affiliates/forms.py index 02a29e3d80d2971e01ed6d1d93f32f9c4f05e42e..9aa73a4c85d26b63746eeaaad5073bba819ffc23 100644 --- a/scipost_django/affiliates/forms.py +++ b/scipost_django/affiliates/forms.py @@ -33,11 +33,7 @@ class AffiliateJournalForm(forms.ModelForm): """ publisher = forms.ChoiceField( - choices=[ - (None, "---------"), - ("create", "Create from journal name"), - ] - + list(AffiliatePublisher.objects.values_list("id", "name")), + choices=[(None, "---------"), ("create", "Create from journal name")] ) class Meta: @@ -64,6 +60,10 @@ class AffiliateJournalForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.fields["publisher"].choices += list( + AffiliatePublisher.objects.values_list("id", "name") + ) + self.helper = FormHelper() self.helper.layout = Layout( Field("publisher"), diff --git a/scipost_django/colleges/forms.py b/scipost_django/colleges/forms.py index 1e1ee96fba87bc1ffe050a2d560d1af5742a8260..78239938e0ffbe86c8405ba0d94c7567b5bb3357 100644 --- a/scipost_django/colleges/forms.py +++ b/scipost_django/colleges/forms.py @@ -3,11 +3,12 @@ __license__ = "AGPL v3" import datetime +from itertools import groupby from typing import Any, Dict from django import forms from django.contrib.sessions.backends.db import SessionStore -from django.db.models import F, Q, Count, OuterRef, Subquery +from django.db.models import F, Q, Count, Exists, OuterRef, Subquery from django.db.models.functions import Coalesce from crispy_forms.helper import FormHelper @@ -932,13 +933,10 @@ class FellowshipNominationDecisionForm(forms.ModelForm): class FellowshipNominationVotingRoundSearchForm(forms.Form): - all_rounds = FellowshipNominationVotingRound.objects.all() - nominee = forms.CharField(max_length=100, required=False, label="Nominee") - college = forms.MultipleChoiceField( - choices=College.objects.all().order_by("name").values_list("id", "name"), - required=False, + college = forms.ModelMultipleChoiceField( + queryset=College.objects.all(), required=False ) decision = forms.ChoiceField( @@ -1320,34 +1318,12 @@ class FellowshipInvitationResponseForm(forms.ModelForm): class FellowshipsMonitorSearchForm(forms.Form): form_id = "fellowships-monitor-search-form" - all_fellowships = Fellowship.objects.all() - fellowships_colleges = all_fellowships.values_list("college", flat=True).distinct() - fellowships_acad_fields = all_fellowships.values("college__acad_field") fellow = forms.CharField(max_length=100, required=False, label="Fellow") - college = forms.MultipleChoiceField( - choices=College.objects.filter(id__in=fellowships_colleges) - .order_by("name") - .values_list("id", "name"), - required=False, - ) + college = forms.MultipleChoiceField(required=False) - # Specialty multiple-choice grouped by the academic field that contains it. - acad_fields = AcademicField.objects.filter( - colleges__in=fellowships_acad_fields - ).values_list("name", "id") - specialty_grouped_choices = [ - ( - field_name, - tuple( - Specialty.objects.filter(acad_field=field_id).values_list("id", "name") - ), - ) - for (field_name, field_id) in acad_fields - ] specialties = forms.MultipleChoiceField( - choices=specialty_grouped_choices, label="Specialties", required=False, ) @@ -1413,6 +1389,43 @@ class FellowshipsMonitorSearchForm(forms.Form): self.session_key = kwargs.pop("session_key", None) super().__init__(*args, **kwargs) + fellowships_colleges = ( + Fellowship.objects.all().values_list("college", flat=True).distinct() + ) + + self.fields["college"].choices = ( + College.objects.annotate( + has_fellows=Exists(Fellowship.objects.filter(college=OuterRef("id"))) + ) + .filter(has_fellows=True) + .order_by("name") + .values_list("id", "name") + ) + + # Specialty multiple-choice grouped by the academic field that contains it. + fellowships_acad_fields = Fellowship.objects.all().values("college__acad_field") + + specialties_with_fellows = list( + Specialty.objects.annotate( + has_fellows=Exists( + Fellowship.objects.filter( + contributor__profile__specialties=OuterRef("id") + ) + ) + ) + .filter(has_fellows=True) + .order_by("acad_field__name", "name") + ) + self.fields["specialties"].choices = [ + ( + acad_field_name, + [(specialty.pk, specialty.name) for specialty in specialties], + ) + for acad_field_name, specialties in groupby( + specialties_with_fellows, key=lambda x: x.acad_field.name + ) + ] + # Set the initial values of the form fields from the session data # if self.session_key: # session = SessionStore(session_key=self.session_key) diff --git a/scipost_django/ontology/models/specialty.py b/scipost_django/ontology/models/specialty.py index da6ac67112e8a0f6a9daaf7f2dc3b08f98ceaaec..ad0d1d0410b436bb8800977e830656d003f7ba7a 100644 --- a/scipost_django/ontology/models/specialty.py +++ b/scipost_django/ontology/models/specialty.py @@ -4,17 +4,22 @@ __license__ = "AGPL v3" from django.db import models +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ontology.models import AcademicField, Topic + class Specialty(models.Model): """ A principal division of an AcademicField. """ - acad_field = models.ForeignKey( + acad_field = models.ForeignKey["AcademicField"]( "ontology.AcademicField", on_delete=models.CASCADE, related_name="specialties" ) - topics = models.ManyToManyField( + topics = models.ManyToManyField["Specialty", "Topic"]( "ontology.Topic", related_name="specialties", blank=True, diff --git a/scipost_django/production/forms.py b/scipost_django/production/forms.py index 6fca8db8cec57a22c79f7386326d8214d686f692..3df1fdd6cb60b68ade945d0170b0324e1bcab551 100644 --- a/scipost_django/production/forms.py +++ b/scipost_django/production/forms.py @@ -312,54 +312,11 @@ class ProductionStreamSearchForm(forms.Form): title = forms.CharField(max_length=512, required=False) identifier = forms.CharField(max_length=128, required=False) - all_streams = ProductionStream.objects.ongoing() - - stream_journals = all_streams.values_list( - "submission__editorialdecision__for_journal", flat=True - ).distinct() - stream_proceedings = all_streams.values_list( - "submission__proceedings", flat=True - ).distinct() - stream_officers = all_streams.values_list("officer", flat=True).distinct() - stream_supervisors = all_streams.values_list("supervisor", flat=True).distinct() - - journal = forms.MultipleChoiceField( - choices=Journal.objects.active() - .filter(id__in=stream_journals) - .order_by("name") - .values_list("id", "name"), - required=False, - ) - proceedings = forms.MultipleChoiceField( - choices=Proceedings.objects.all() - .filter(id__in=stream_proceedings) - .order_by("-submissions_close") - # Short name is `event_suffix` if set, otherwise `event_name` - .annotate( - short_name=Coalesce(NullIf("event_suffix", Value("")), "event_name") - ).values_list("id", "short_name"), - required=False, - ) - officer = forms.MultipleChoiceField( - choices=[(0, "Unassigned")] - + [ - (prod_user.id, str(prod_user)) - for prod_user in ProductionUser.objects.active() - .filter(id__in=stream_officers) - .order_by("-user__id") - ], - required=False, - ) - supervisor = forms.MultipleChoiceField( - choices=[(0, "Unassigned")] - + [ - (prod_user.id, str(prod_user)) - for prod_user in ProductionUser.objects.active() - .filter(id__in=stream_supervisors) - .order_by("-user__id") - ], - required=False, - ) + journal = forms.MultipleChoiceField(choices=[], required=False) + proceedings = forms.MultipleChoiceField(choices=[], required=False) + officer = forms.MultipleChoiceField(choices=[(0, "Unassigned")], required=False) + supervisor = forms.MultipleChoiceField(choices=[(0, "Unassigned")], required=False) + status = forms.MultipleChoiceField( # Use short status names from their internal (code) name choices=[ @@ -396,6 +353,39 @@ class ProductionStreamSearchForm(forms.Form): self.session_key = kwargs.pop("session_key", None) super().__init__(*args, **kwargs) + all_streams = ProductionStream.objects.ongoing() + + self.fields["journal"].choices = ( + Journal.objects.active() + .filter( + id__in=all_streams.values("submission__editorialdecision__for_journal") + ) + .order_by("name") + .values_list("id", "name") + ) + self.fields["proceedings"].choices = ( + Proceedings.objects.all() + .filter(id__in=all_streams.values("submission__proceedings")) + .order_by("-submissions_close") + # Short name is `event_suffix` if set, otherwise `event_name` + .annotate( + short_name=Coalesce(NullIf("event_suffix", Value("")), "event_name") + ) + .values_list("id", "short_name") + ) + self.fields["officer"].choices = [(0, "Unassigned")] + list( + ProductionUser.objects.active() + .filter(id__in=all_streams.values("officer")) + .order_by("-user__id") + .values_list("id", "name") + ) + self.fields["supervisor"].choices = [(0, "Unassigned")] + list( + ProductionUser.objects.active() + .filter(id__in=all_streams.values("supervisor")) + .order_by("-user__id") + .values_list("id", "name") + ) + # Set the initial values of the form fields from the session data # if self.session_key: # session = SessionStore(session_key=self.session_key) diff --git a/scipost_django/submissions/forms/__init__.py b/scipost_django/submissions/forms/__init__.py index a592e3a83c5b9041938e34871d310a245fdc7802..6ff48cb3fe9c0ab1513cf978e122f57dc96408b4 100644 --- a/scipost_django/submissions/forms/__init__.py +++ b/scipost_django/submissions/forms/__init__.py @@ -1309,15 +1309,7 @@ class SubmissionForm(forms.ModelForm): required_css_class = "required-asterisk" collection = forms.ChoiceField( - choices=[(None, "None")] - + list( - Collection.objects.all() - .filter(is_active=True) - .order_by("-event_start_date") - # Short name is `event_suffix` if set, otherwise `event_name` - .annotate(name_with_series=Concat("series__name", Value(" - "), "name")) - .values_list("id", "name_with_series") - ), + choices=[(None, "None")], help_text="If your submission is part of a collection (e.g. Les Houches), please select it from the list.<br>If your target collection is missing, please contact techsupport.", required=False, ) @@ -1563,6 +1555,17 @@ class SubmissionForm(forms.ModelForm): "agree_to_terms", ) + self.fields["collection"].choices += ( + list( + Collection.objects.all() + .filter(is_active=True) + .order_by("-event_start_date") + # Short name is `event_suffix` if set, otherwise `event_name` + .annotate(name_with_series=Concat("series__name", Value(" - "), "name")) + .values_list("id", "name_with_series") + ), + ) + if self.preprint_server.name == "SciPost": # SciPost identifier will be auto-generated del self.fields["identifier_w_vn_nr"]