From 6ee0604e757d04d8ae824133afa8514217512e84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org>
Date: Sat, 29 Jan 2022 12:15:58 +0100
Subject: [PATCH] Use `profile_id` instead of `profile` to accelerate form
 rendering

---
 scipost_django/colleges/forms.py              | 56 +++++++++++--------
 .../colleges/_hx_nomination_form.html         |  1 +
 scipost_django/colleges/views.py              |  2 +-
 3 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/scipost_django/colleges/forms.py b/scipost_django/colleges/forms.py
index c83fa4835..4ccc6f387 100644
--- a/scipost_django/colleges/forms.py
+++ b/scipost_django/colleges/forms.py
@@ -298,28 +298,28 @@ class FellowshipNominationForm(forms.ModelForm):
     #     required=False,
     #     widget=forms.Textarea()
     # )
+    profile_id = forms.IntegerField()
 
     class Meta:
         model = FellowshipNomination
-        fields = [ 'college', 'profile', 'nominated_by', 'nominator_comments' ]
-        # widgets = {
-        #     'nominated_by': forms.HiddenInput()
-        # }
+        fields = [
+            'profile_id', 'nominated_by',    # hidden
+            'college', 'nominator_comments'  # visible
+        ]
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        #self.fields['profile'].queryset = Profile.objects.none()
-        self.fields['profile'].widget.attrs['readonly'] = True
+        #self.fields['profile'].widget.attrs['readonly'] = True
+        self.profile = None
         self.helper = FormHelper()
         self.helper.layout = Layout(
+            Field('profile_id', type='hidden'),
             Field('nominated_by', type='hidden'),
             Div(
-                Div(FloatingField('college'), css_class='col-lg-6'),
-                Div(FloatingField('profile'), css_class='col-lg-6'),
-                css_class='row'
+                Field('nominator_comments')
             ),
             Div(
-                Div(Field('nominator_comments'), css_class='col-lg-8'),
+                Div(FloatingField('college'), css_class='col-lg-8'),
                 Div(
                     ButtonHolder(Submit('submit', 'Submit', css_class='btn btn-danger')),
                     css_class="col-lg-4"
@@ -328,7 +328,7 @@ class FellowshipNominationForm(forms.ModelForm):
             ),
         )
 
-    def clean_profile(self):
+    def clean_profile_id(self):
         """
         Requirements:
 
@@ -337,15 +337,21 @@ class FellowshipNominationForm(forms.ModelForm):
         - no 'not elected' decision in last 2 years
         - no invitation was turned down in the last 2 years
         """
-        profile = self.cleaned_data['profile']
+        profile_id = self.cleaned_data['profile_id']
+        try:
+            self.profile = Profile.objects.get(pk=profile_id)
+        except Profile.DoesNotExist:
+            self.add_error(
+                'profile_id',
+                'Profile not found')
         if Fellowship.objects.active().regular_or_senior().filter(
-                contributor__profile=profile).exists():
+                contributor__profile=self.profile).exists():
             self.add_error(
-                'profile',
+                'profile_id',
                 'This Profile is associated to an active Fellowship.'
             )
         latest_nomination = FellowshipNomination.objects.filter(
-            profile=self.cleaned_data.get('profile')).first()
+            profile=self.profile).first()
         if latest_nomination:
             try:
                 if (latest_nomination.decision.fixed_on +
@@ -354,35 +360,41 @@ class FellowshipNominationForm(forms.ModelForm):
                         try:
                             if latest_nomination.invitation.declined:
                                 self.add_error(
-                                    'profile',
+                                    'profile_id',
                                     'Invitation declined less that 2 years ago. '
                                     'Wait to try again.')
                             else:
                                 self.add_error(
-                                    'profile',
+                                    'profile_id',
                                     'Already elected, invitation in process.')
                         except AttributeError:
                             self.add_error(
-                                'profile',
+                                'profile_id',
                                 'Already elected, invitation pending.')
                     self.add_error(
-                        'profile',
+                        'profile_id',
                         'Election failed less that 2 years ago. Must wait.')
             except AttributeError: # no decision yet
                 self.add_error(
-                    'profile',
+                    'profile_id',
                     'This Profile is associated to an ongoing Nomination process.')
-        return profile
+        return profile_id
 
     def clean(self):
         data = super().clean()
-        if data['college'].acad_field != data['profile'].acad_field:
+        if data['college'].acad_field != self.profile.acad_field:
             self.add_error(
                 'college',
                 'Mismatch between college.acad_field and profile.acad_field.'
             )
         return data
 
+    def save(self):
+        nomination = super().save(commit=False)
+        nomination.profile = self.profile
+        nomination.save()
+        return nomination
+
 
 class FellowshipNominationSearchForm(forms.Form):
     """Filter a FellowshipNomination queryset using basic search fields."""
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_form.html b/scipost_django/colleges/templates/colleges/_hx_nomination_form.html
index 7971f04e9..75cc8ac43 100644
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_form.html
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_form.html
@@ -1,4 +1,5 @@
 {% load crispy_forms_tags %}
+<h3>Nomination to Fellowship for {{ profile }}</h3>
 <form
     hx-post="{% url 'colleges:_hx_nomination_form' profile_id=profile.pk %}"
     hx-target="#nomination_form_response"
diff --git a/scipost_django/colleges/views.py b/scipost_django/colleges/views.py
index bd9e2f61f..e1b349831 100644
--- a/scipost_django/colleges/views.py
+++ b/scipost_django/colleges/views.py
@@ -561,7 +561,7 @@ def _hx_nomination_form(request, profile_id):
             f'<div class="bg-success text-white p-2 ">{nomination.profile} '
             f'successfully nominated to {nomination.college}.</div>')
     profile = get_object_or_404(Profile, pk=profile_id)
-    nomination_form.fields['profile'].initial = profile
+    nomination_form.fields['profile_id'].initial = profile.pk
     nomination_form.fields['nominated_by'].initial = request.user.contributor
     context = {
         'profile': profile,
-- 
GitLab