diff --git a/opentech/apply/funds/forms.py b/opentech/apply/funds/forms.py index 05d1ed80578271c318b6f8a5421baa4ead5470d6..84ab400ad95ebb6e153eac5099cb0441b983ac4b 100644 --- a/opentech/apply/funds/forms.py +++ b/opentech/apply/funds/forms.py @@ -17,7 +17,39 @@ from .widgets import Select2MultiCheckboxesWidget, MetaCategorySelect2Widget from .workflow import get_action_mapping -class ProgressSubmissionForm(forms.ModelForm): +class ApplicationSubmissionModelForm(forms.ModelForm): + """ + Application Submission model's save method performs several operations + which are not required in forms which update fields like status, partners etc. + It also has a side effect of creating a new file uploads every time with long filenames (#1572). + """ + + def save(self, commit=True): + """ + Save this form's self.instance object if commit=True. Otherwise, add + a save_m2m() method to the form which can be called after the instance + is saved manually at a later time. Return the model instance. + https://github.com/django/django/blob/5d9cf79baf07fc4aed7ad1b06990532a65378155/django/forms/models.py#L444 + """ + if self.errors: + raise ValueError( + "The %s could not be %s because the data didn't validate." % ( + self.instance._meta.object_name, + 'created' if self.instance._state.adding else 'changed', + ) + ) + if commit: + # If committing, save the instance and the m2m data immediately. + self.instance.save(skip_custom=True) + self._save_m2m() + else: + # If not committing, add a method to the form to allow deferred + # saving of m2m data. + self.save_m2m = self._save_m2m + return self.instance + + +class ProgressSubmissionForm(ApplicationSubmissionModelForm): action = forms.ChoiceField(label='Take action') class Meta: @@ -59,7 +91,7 @@ class BatchProgressSubmissionForm(forms.Form): return action -class ScreeningSubmissionForm(forms.ModelForm): +class ScreeningSubmissionForm(ApplicationSubmissionModelForm): class Meta: model = ApplicationSubmission @@ -73,7 +105,8 @@ class ScreeningSubmissionForm(forms.ModelForm): self.should_show = True -class UpdateSubmissionLeadForm(forms.ModelForm): +class UpdateSubmissionLeadForm(ApplicationSubmissionModelForm): + class Meta: model = ApplicationSubmission fields = ('lead',) @@ -121,7 +154,7 @@ class BatchUpdateSubmissionLeadForm(forms.Form): return None -class UpdateReviewersForm(forms.ModelForm): +class UpdateReviewersForm(ApplicationSubmissionModelForm): reviewer_reviewers = forms.ModelMultipleChoiceField( queryset=User.objects.reviewers().only('pk', 'full_name'), widget=Select2MultiCheckboxesWidget(attrs={'data-placeholder': 'Reviewers'}), @@ -300,7 +333,7 @@ def make_role_reviewer_fields(): return role_fields -class UpdatePartnersForm(forms.ModelForm): +class UpdatePartnersForm(ApplicationSubmissionModelForm): partner_reviewers = forms.ModelMultipleChoiceField( queryset=User.objects.partners(), widget=Select2MultiCheckboxesWidget(attrs={'data-placeholder': 'Partners'}), @@ -361,7 +394,7 @@ class GroupedModelMultipleChoiceField(forms.ModelMultipleChoiceField): return {'label': super().label_from_instance(obj), 'disabled': not obj.is_leaf()} -class UpdateMetaCategoriesForm(forms.ModelForm): +class UpdateMetaCategoriesForm(ApplicationSubmissionModelForm): meta_categories = GroupedModelMultipleChoiceField( queryset=None, # updated in init method widget=MetaCategorySelect2Widget(attrs={'data-placeholder': 'Meta categories'}), diff --git a/opentech/apply/funds/models/submissions.py b/opentech/apply/funds/models/submissions.py index d20669b5692dfd6769156d559799fa6078e82672..20e91b8dd24ab43a2b5ee8dce6d74c2b8d1b25c7 100644 --- a/opentech/apply/funds/models/submissions.py +++ b/opentech/apply/funds/models/submissions.py @@ -598,10 +598,12 @@ class ApplicationSubmission( f.save() self.form_data[field.id] = file - def save(self, *args, update_fields=list(), **kwargs): + def save(self, *args, update_fields=list(), skip_custom=False, **kwargs): if update_fields and 'form_data' not in update_fields: # We don't want to use this approach if the user is sending data return super().save(*args, update_fields=update_fields, **kwargs) + elif skip_custom: + return super().save(*args, **kwargs) if self.is_draft: raise ValueError('Cannot save with draft data')