refactor: add person update form fields to initial

This commit is contained in:
James Graham
2021-01-15 17:45:55 +00:00
parent f94627e4c8
commit 4cfee6362d
3 changed files with 64 additions and 12 deletions

View File

@@ -1,6 +1,4 @@
"""
Forms for creating / updating models belonging to the 'people' app.
"""
"""Forms for creating / updating models belonging to the 'people' app."""
import typing
@@ -28,11 +26,7 @@ class OrganisationForm(forms.ModelForm):
"""Form for creating / updating an instance of :class:`Organisation`."""
class Meta:
model = models.Organisation
fields = [
'name',
'latitude',
'longitude'
]
fields = ['name', 'latitude', 'longitude']
class PersonForm(forms.ModelForm):
@@ -59,6 +53,8 @@ class DynamicAnswerSetBase(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
initial = kwargs.get('initial', {})
for question in self.question_model.objects.all():
field_class = self.field_class
field_widget = self.field_widget
@@ -67,11 +63,14 @@ class DynamicAnswerSetBase(forms.Form):
field_class = forms.ModelMultipleChoiceField
field_widget = Select2MultipleWidget
field_name = f'question_{question.pk}'
field = field_class(label=question,
queryset=question.answers,
widget=field_widget,
required=self.field_required)
self.fields['question_{}'.format(question.pk)] = field
required=self.field_required,
initial=initial.get(field_name, None))
self.fields[field_name] = field
class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase):

View File

@@ -190,5 +190,50 @@ class PersonAnswerSet(AnswerSet):
#: Longitude for displaying location on a map
longitude = models.FloatField(blank=True, null=True)
def as_dict(self):
"""Get the answers from this set as a dictionary for use in Form.initial."""
exclude_fields = {
'id',
'timestemp',
'replaced_timestamp',
'person_id',
'question_answers',
'themes',
}
def field_value_repr(field):
"""Get the representation of a field's value as required by Form.initial."""
attr_val = getattr(self, field.attname)
# Relation fields need to return PKs
if isinstance(field, models.ManyToManyField):
return [obj.pk for obj in attr_val.all()]
if isinstance(field, models.ForeignKey):
return attr_val.pk
return attr_val
answers = {
field.attname: field_value_repr(field)
for field in self._meta.get_fields()
if field.attname not in exclude_fields
}
for answer in self.question_answers.all():
question = answer.question
field_name = f'question_{question.pk}'
if question.is_multiple_choice:
if field_name not in answers:
answers[field_name] = []
answers[field_name].append(answer.pk)
else:
answers[field_name] = answer.pk
return answers
def get_absolute_url(self):
return self.person.get_absolute_url()

View File

@@ -84,9 +84,17 @@ class PersonUpdateView(permissions.UserIsLinkedPersonMixin, UpdateView):
return context
def get_initial(self) -> typing.Dict[str, typing.Any]:
return {
try:
previous_answers = self.object.current_answers.as_dict()
except AttributeError:
previous_answers = {}
previous_answers.update({
'person_id': self.object.id,
}
})
return previous_answers
def get_form_kwargs(self) -> typing.Dict[str, typing.Any]:
"""Remove instance from form kwargs as it's a person, but expects a PersonAnswerSet."""