Skip to content

Forms

hypha.apply.funds.forms

ApplicationSubmissionModelForm

Bases: 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).

save

save(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

Source code in hypha/apply/funds/forms.py
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

ProgressSubmissionForm

ProgressSubmissionForm(*args, **kwargs)

Bases: ApplicationSubmissionModelForm

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, **kwargs):
    self.user = kwargs.pop("user")
    super().__init__(*args, **kwargs)
    choices = list(self.instance.get_actions_for_user(self.user))
    # Sort the transitions by the order they are listed.
    sort_by = list(self.instance.phase.transitions.keys())
    choices.sort(key=lambda k: sort_by.index(k[0]))
    action_field = self.fields["action"]
    action_field.choices = choices

action class-attribute instance-attribute

action = ChoiceField(label=gettext_lazy('Take action'))

user instance-attribute

user = pop('user')

Meta

model class-attribute instance-attribute
fields class-attribute instance-attribute
fields = []

save

save(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

Source code in hypha/apply/funds/forms.py
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

BatchProgressSubmissionForm

BatchProgressSubmissionForm(*args, round=None, **kwargs)

Bases: Form

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, round=None, **kwargs):
    self.user = kwargs.pop("user")
    super().__init__(*args, **kwargs)
    workflow = round and round.workflow
    self.action_mapping = get_action_mapping(workflow)
    choices = [
        (action, detail["display"])
        for action, detail in self.action_mapping.items()
    ]
    self.fields["action"].choices = choices

action class-attribute instance-attribute

action = ChoiceField(label=gettext_lazy('Take action'))

submissions class-attribute instance-attribute

submissions = CharField(widget=HiddenInput(attrs={'class': 'js-submissions-id'}))

user instance-attribute

user = pop('user')

action_mapping instance-attribute

action_mapping = get_action_mapping(workflow)

clean_submissions

clean_submissions()
Source code in hypha/apply/funds/forms.py
def clean_submissions(self):
    value = self.cleaned_data["submissions"]
    submission_ids = [int(submission) for submission in value.split(",")]
    return ApplicationSubmission.objects.filter(id__in=submission_ids)

clean_action

clean_action()
Source code in hypha/apply/funds/forms.py
def clean_action(self):
    value = self.cleaned_data["action"]
    action = self.action_mapping[value]["transitions"]
    return action

UpdateSubmissionLeadForm

UpdateSubmissionLeadForm(*args, **kwargs)

Bases: ApplicationSubmissionModelForm

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    lead_field = self.fields["lead"]
    lead_field.label = _("New lead")
    lead_field.queryset = lead_field.queryset.exclude(id=self.instance.lead.id)

Meta

model class-attribute instance-attribute
fields class-attribute instance-attribute
fields = ('lead')

save

save(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

Source code in hypha/apply/funds/forms.py
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

BatchUpdateSubmissionLeadForm

BatchUpdateSubmissionLeadForm(*args, round=None, **kwargs)

Bases: Form

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, round=None, **kwargs):
    self.user = kwargs.pop("user")
    super().__init__(*args, **kwargs)
    self.fields["lead"].choices = [
        (staff.id, staff) for staff in User.objects.staff()
    ]

lead class-attribute instance-attribute

lead = ChoiceField(label=gettext_lazy('Lead'))

submissions class-attribute instance-attribute

submissions = CharField(widget=HiddenInput(attrs={'class': 'js-submissions-id'}))

user instance-attribute

user = pop('user')

clean_lead

clean_lead()
Source code in hypha/apply/funds/forms.py
def clean_lead(self):
    value = self.cleaned_data["lead"]
    return User.objects.get(id=value)

clean_submissions

clean_submissions()
Source code in hypha/apply/funds/forms.py
def clean_submissions(self):
    value = self.cleaned_data["submissions"]
    submission_ids = [int(submission) for submission in value.split(",")]
    return ApplicationSubmission.objects.filter(id__in=submission_ids)

BatchDeleteSubmissionForm

BatchDeleteSubmissionForm(*args, round=None, **kwargs)

Bases: Form

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, round=None, **kwargs):
    self.user = kwargs.pop("user")
    super().__init__(*args, **kwargs)

submissions class-attribute instance-attribute

submissions = CharField(widget=HiddenInput(attrs={'class': 'js-submissions-id'}))

user instance-attribute

user = pop('user')

clean_submissions

clean_submissions()
Source code in hypha/apply/funds/forms.py
def clean_submissions(self):
    value = self.cleaned_data["submissions"]
    submission_ids = [int(submission) for submission in value.split(",")]
    return ApplicationSubmission.objects.filter(id__in=submission_ids)

BatchArchiveSubmissionForm

BatchArchiveSubmissionForm(*args, round=None, **kwargs)

Bases: Form

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, round=None, **kwargs):
    self.user = kwargs.pop("user")
    super().__init__(*args, **kwargs)

submissions class-attribute instance-attribute

submissions = CharField(widget=HiddenInput(attrs={'class': 'js-submissions-id'}))

user instance-attribute

user = pop('user')

clean_submissions

clean_submissions()
Source code in hypha/apply/funds/forms.py
def clean_submissions(self):
    value = self.cleaned_data["submissions"]
    submission_ids = [int(submission) for submission in value.split(",")]
    return ApplicationSubmission.objects.filter(id__in=submission_ids)

UpdateReviewersForm

UpdateReviewersForm(*args, **kwargs)

Bases: ApplicationSubmissionModelForm

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, **kwargs):
    self.user = kwargs.pop("user")
    if kwargs.get("instance"):
        # Providing initials(from model's instance) to BaseModelForm
        kwargs["initial"] = model_form_initial(
            kwargs.get("instance"), self._meta.fields, self._meta.exclude
        )
    super().__init__(*args, **kwargs)

    # convert a python dict to orderedDict, to use move_to_end method
    self.fields = OrderedDict(self.fields)

    assigned_roles = {
        assigned.role: assigned.reviewer
        for assigned in self.instance.assigned.filter(role__isnull=False)
    }

    self.role_fields = {}
    field_data = make_role_reviewer_fields()

    for data in field_data:
        field_name = data["field_name"]
        self.fields[field_name] = data["field"]
        self.role_fields[field_name] = data["role"]
        self.fields[field_name].initial = assigned_roles.get(data["role"])

    self.submitted_reviewers = User.objects.filter(
        id__in=self.instance.assigned.reviewed().values("reviewer"),
    )

    if can_change_external_reviewers(user=self.user, submission=self.instance):
        reviewers = self.instance.reviewers.all().only("pk")
        self.prepare_field(
            "reviewer_reviewers",
            initial=reviewers,
            excluded=self.submitted_reviewers,
        )

        # Move the non-role reviewers field to the end of the field list
        self.fields.move_to_end("reviewer_reviewers")
    else:
        self.fields.pop("reviewer_reviewers")

reviewer_reviewers class-attribute instance-attribute

reviewer_reviewers = ModelMultipleChoiceField(queryset=only('pk', 'full_name'), label=gettext_lazy('External Reviewers'), required=False)

user instance-attribute

user = pop('user')

fields instance-attribute

fields = OrderedDict(fields)

role_fields instance-attribute

role_fields = {}

submitted_reviewers instance-attribute

submitted_reviewers = filter(id__in=values('reviewer'))

Meta

model class-attribute instance-attribute
fields class-attribute instance-attribute
fields = []

prepare_field

prepare_field(field_name, initial, excluded)
Source code in hypha/apply/funds/forms.py
def prepare_field(self, field_name, initial, excluded):
    field = self.fields[field_name]
    field.queryset = field.queryset.exclude(id__in=excluded)
    field.initial = initial

clean

clean()
Source code in hypha/apply/funds/forms.py
def clean(self):
    cleaned_data = super().clean()
    role_reviewers = [
        user
        for field, user in self.cleaned_data.items()
        if field in self.role_fields and user
    ]

    for field, role in self.role_fields.items():
        assigned_reviewer = AssignedReviewers.objects.filter(
            role=role, submission=self.instance
        ).last()
        if (
            assigned_reviewer
            and (not cleaned_data[field] and assigned_reviewer.reviewer.is_active)
            and assigned_reviewer.reviewer in self.submitted_reviewers
        ):
            self.add_error(
                field,
                _("Can't unassign, just change, because review already submitted"),
            )
            break

    # If any of the users match and are set to multiple roles, throw an error
    if len(role_reviewers) != len(set(role_reviewers)) and any(role_reviewers):
        self.add_error(None, _("Users cannot be assigned to multiple roles."))

    return cleaned_data

save

save(*args, **kwargs)
  1. Update role reviewers
  2. Update non-role reviewers 2a. Remove those not on form 2b. Add in any new non-role reviewers selected
Source code in hypha/apply/funds/forms.py
def save(self, *args, **kwargs):
    """
    1. Update role reviewers
    2. Update non-role reviewers
        2a. Remove those not on form
        2b. Add in any new non-role reviewers selected
    """
    with disable_reference_index_auto_update():
        instance = super().save(*args, **kwargs)

        # 1. Update role reviewers
        assigned_roles = {
            role: self.cleaned_data[field]
            for field, role in self.role_fields.items()
        }
        for role, reviewer in assigned_roles.items():
            if reviewer:
                AssignedReviewers.objects.update_role(role, reviewer, instance)
            else:
                AssignedReviewers.objects.filter(
                    role=role, submission=instance, review__isnull=True
                ).delete()

        # 2. Update non-role reviewers
        # 2a. Remove those not on form
        if can_change_external_reviewers(submission=self.instance, user=self.user):
            reviewers = self.cleaned_data.get("reviewer_reviewers")
            assigned_reviewers = instance.assigned.without_roles()
            assigned_reviewers.never_tried_to_review().exclude(
                reviewer__in=reviewers
            ).delete()

            remaining_reviewers = assigned_reviewers.values_list(
                "reviewer_id", flat=True
            )

            # 2b. Add in any new non-role reviewers selected
            AssignedReviewers.objects.bulk_create_reviewers(
                [
                    reviewer
                    for reviewer in reviewers
                    if reviewer.id not in remaining_reviewers
                ],
                instance,
            )

        return instance

BatchUpdateReviewersForm

BatchUpdateReviewersForm(*args, user=None, round=None, **kwargs)

Bases: Form

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, user=None, round=None, **kwargs):
    super().__init__(*args, **kwargs)
    self.request = kwargs.pop("request", None)
    self.user = user
    self.fields = OrderedDict(self.fields)

    self.role_fields = {}
    field_data = make_role_reviewer_fields()

    for data in field_data:
        field_name = data["field_name"]
        self.fields[field_name] = data["field"]
        self.role_fields[field_name] = data["role"]

    self.fields.move_to_end("external_reviewers")

submissions class-attribute instance-attribute

submissions = CharField(widget=HiddenInput(attrs={'class': 'js-submissions-id'}))

external_reviewers class-attribute instance-attribute

external_reviewers = ModelMultipleChoiceField(queryset=only('pk', 'full_name'), widget=Select2MultiCheckboxesWidget(attrs={'data-placeholder': 'Select...'}), label=gettext_lazy('External Reviewers'), required=False)

request instance-attribute

request = pop('request', None)

user instance-attribute

user = user

fields instance-attribute

fields = OrderedDict(fields)

role_fields instance-attribute

role_fields = {}

clean_submissions

clean_submissions()
Source code in hypha/apply/funds/forms.py
def clean_submissions(self):
    value = self.cleaned_data["submissions"]
    submission_ids = [int(submission) for submission in value.split(",")]
    return ApplicationSubmission.objects.filter(id__in=submission_ids)

clean

clean()
Source code in hypha/apply/funds/forms.py
def clean(self):
    cleaned_data = super().clean()
    external_reviewers = self.cleaned_data["external_reviewers"]
    submissions = self.cleaned_data["submissions"]
    if external_reviewers:
        # User needs to be superuser or lead of all selected submissions.

        if not all(
            can_change_external_reviewers(submission=s, user=self.user)
            for s in submissions
        ):
            self.add_error(
                "external_reviewers",
                _(
                    "Make sure all submissions support external reviewers and you are lead for all the selected submissions."
                ),
            )

    role_reviewers = [
        user
        for field, user in self.cleaned_data.items()
        if field in self.role_fields and user
    ]

    # If any of the users match and are set to multiple roles, throw an error
    if len(role_reviewers) != len(set(role_reviewers)) and any(role_reviewers):
        self.add_error(None, _("Users cannot be assigned to multiple roles."))

    return cleaned_data

submissions_cant_have_external_reviewers

submissions_cant_have_external_reviewers(submissions)
Source code in hypha/apply/funds/forms.py
def submissions_cant_have_external_reviewers(self, submissions):
    for submission in submissions:
        if not submission.stage.has_external_review:
            return True
    return False

UpdatePartnersForm

UpdatePartnersForm(*args, **kwargs)

Bases: ApplicationSubmissionModelForm

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, **kwargs):
    kwargs.pop("user")
    super().__init__(*args, **kwargs)
    partners = self.instance.partners.all()
    self.submitted_partners = User.objects.partners().filter(
        id__in=self.instance.reviews.values("author")
    )

    partner_field = self.fields["partner_reviewers"]

    # If applicant is also a partner, they should not be allowed to be a partner on their own application
    partner_field.queryset = partner_field.queryset.exclude(
        Q(id__in=self.submitted_partners) | Q(id=self.instance.user.id)
    )
    partner_field.initial = partners

partner_reviewers class-attribute instance-attribute

partner_reviewers = ModelMultipleChoiceField(queryset=partners(), label=gettext_lazy('Partners'), required=False)

submitted_partners instance-attribute

submitted_partners = filter(id__in=values('author'))

Meta

model class-attribute instance-attribute
fields class-attribute instance-attribute
fields = []

save

save(*args, **kwargs)
Source code in hypha/apply/funds/forms.py
def save(self, *args, **kwargs):
    instance = super().save(*args, **kwargs)

    instance.partners.set(
        self.cleaned_data["partner_reviewers"] | self.submitted_partners
    )
    return instance

GroupedModelChoiceIterator

GroupedModelChoiceIterator(field, groupby)

Bases: ModelChoiceIterator

Source code in hypha/apply/funds/forms.py
def __init__(self, field, groupby):
    self.groupby = groupby
    super().__init__(field)

groupby instance-attribute

groupby = groupby

GroupedModelMultipleChoiceField

GroupedModelMultipleChoiceField(*args, choices_groupby, **kwargs)

Bases: ModelMultipleChoiceField

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, choices_groupby, **kwargs):
    if isinstance(choices_groupby, str):
        choices_groupby = methodcaller(choices_groupby)
    elif not callable(choices_groupby):
        raise TypeError(
            "choices_groupby must either be a str or a callable accepting a single argument"
        )
    self.iterator = partial(GroupedModelChoiceIterator, groupby=choices_groupby)
    super().__init__(*args, **kwargs)

iterator instance-attribute

iterator = partial(GroupedModelChoiceIterator, groupby=choices_groupby)

label_from_instance

label_from_instance(obj)
Source code in hypha/apply/funds/forms.py
def label_from_instance(self, obj):
    return {
        "label": super().label_from_instance(obj),
        "disabled": not obj.is_leaf(),
    }

UpdateMetaTermsForm

UpdateMetaTermsForm(*args, **kwargs)

Bases: ApplicationSubmissionModelForm

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, **kwargs):
    kwargs.pop("user")
    super().__init__(*args, **kwargs)
    self.fields["meta_terms"].queryset = MetaTerm.get_root_descendants().exclude(
        depth=2
    )
    # Set initial values for meta_terms based on the instance if available
    if self.instance.pk:
        self.fields["meta_terms"].initial = self.instance.meta_terms.values_list(
            "id", flat=True
        )

meta_terms class-attribute instance-attribute

meta_terms = GroupedModelMultipleChoiceField(queryset=None, widget=MetaTermSelect2Widget(attrs={'data-placeholder': 'Select...'}), label=gettext_lazy('Meta terms'), choices_groupby='get_parent', required=False, help_text=gettext_lazy('Meta terms are hierarchical in nature.'))

Meta

model class-attribute instance-attribute
fields class-attribute instance-attribute
fields = []

save

save(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

Source code in hypha/apply/funds/forms.py
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

CreateReminderForm

CreateReminderForm(*args, instance=None, user=None, **kwargs)

Bases: ModelForm

Source code in hypha/apply/funds/forms.py
def __init__(self, *args, instance=None, user=None, **kwargs):
    super().__init__(*args, **kwargs)
    self.user = user

    if instance:
        self.fields["submission"].initial = instance.id

submission class-attribute instance-attribute

submission = ModelChoiceField(queryset=filter(), widget=HiddenInput())

time class-attribute instance-attribute

time = DateField()

user instance-attribute

user = user

Meta

model class-attribute instance-attribute
model = Reminder
fields class-attribute instance-attribute
fields = ['title', 'description', 'time', 'action']

save

save(*args, **kwargs)
Source code in hypha/apply/funds/forms.py
def save(self, *args, **kwargs):
    return Reminder.objects.create(
        title=self.cleaned_data["title"],
        description=self.cleaned_data["description"],
        time=self.cleaned_data["time"],
        submission=self.cleaned_data["submission"],
        user=self.user,
    )

make_role_reviewer_fields

make_role_reviewer_fields()
Source code in hypha/apply/funds/forms.py
def make_role_reviewer_fields():
    role_fields = []
    staff_reviewers = User.objects.staff().only("full_name", "pk")

    for role in ReviewerRole.objects.all().order_by("order"):
        role_name = nh3.clean(role.name, tags=set())
        field_name = f"role_reviewer_{role.id}"
        field = forms.ModelChoiceField(
            queryset=staff_reviewers,
            empty_label=_("---"),
            required=False,
            label=mark_safe(
                render_icon(role.icon)
                + _("{role_name} Reviewer").format(role_name=role_name)
            ),
        )
        role_fields.append(
            {
                "role": role,
                "field": field,
                "field_name": field_name,
            }
        )

    return role_fields