feat: add organisation questions to update view

This commit is contained in:
James Graham
2021-02-24 14:59:43 +00:00
parent adf12442a4
commit c8a68d542a
4 changed files with 89 additions and 10 deletions

View File

@@ -57,7 +57,7 @@ class DynamicAnswerSetBase(forms.Form):
field = field_class(label=question, field = field_class(label=question,
queryset=question.answers, queryset=question.answers,
widget=field_widget, widget=field_widget,
required=self.field_required, required=self.field_required and not question.allow_free_text,
initial=initial.get(field_name, None)) initial=initial.get(field_name, None))
self.fields[field_name] = field self.fields[field_name] = field
@@ -67,6 +67,48 @@ class DynamicAnswerSetBase(forms.Form):
self.fields[f'{field_name}_free'] = free_field self.fields[f'{field_name}_free'] = free_field
class OrganisationAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase):
"""Form for variable organisation attributes.
Dynamic fields inspired by https://jacobian.org/2010/feb/28/dynamic-form-generation/
"""
class Meta:
model = models.OrganisationAnswerSet
fields = []
question_model = models.OrganisationQuestion
answer_model = models.OrganisationQuestionChoice
def save(self, commit=True) -> models.OrganisationAnswerSet:
# Save model
self.instance = super().save(commit=False)
self.instance.organisation_id = self.initial['organisation_id']
if commit:
self.instance.save()
# Need to call same_m2m manually since we use commit=False above
self.save_m2m()
if commit:
# Save answers to questions
for key, value in self.cleaned_data.items():
if key.startswith('question_') and value:
if key.endswith('_free'):
# Create new answer from free text
value, _ = self.answer_model.objects.get_or_create(
text=value,
question=self.question_model.objects.get(
pk=key.split('_')[1]))
try:
self.instance.question_answers.add(value)
except TypeError:
# Value is a QuerySet - multiple choice question
self.instance.question_answers.add(*value.all())
return self.instance
class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase): class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase):
"""Form for variable person attributes. """Form for variable person attributes.
@@ -101,7 +143,7 @@ class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase):
answer_model = models.PersonQuestionChoice answer_model = models.PersonQuestionChoice
def save(self, commit=True) -> models.PersonAnswerSet: def save(self, commit=True) -> models.PersonAnswerSet:
# Save Relationship model # Save model
self.instance = super().save(commit=False) self.instance = super().save(commit=False)
self.instance.person_id = self.initial['person_id'] self.instance.person_id = self.initial['person_id']
if commit: if commit:
@@ -110,7 +152,7 @@ class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase):
self.save_m2m() self.save_m2m()
if commit: if commit:
# Save answers to relationship questions # Save answers to questions
for key, value in self.cleaned_data.items(): for key, value in self.cleaned_data.items():
if key.startswith('question_') and value: if key.startswith('question_') and value:
if key.endswith('_free'): if key.endswith('_free'):
@@ -146,11 +188,11 @@ class RelationshipAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase):
answer_model = models.RelationshipQuestionChoice answer_model = models.RelationshipQuestionChoice
def save(self, commit=True) -> models.RelationshipAnswerSet: def save(self, commit=True) -> models.RelationshipAnswerSet:
# Save Relationship model # Save model
self.instance = super().save(commit=commit) self.instance = super().save(commit=commit)
if commit: if commit:
# Save answers to relationship questions # Save answers to questions
for key, value in self.cleaned_data.items(): for key, value in self.cleaned_data.items():
if key.startswith('question_') and value: if key.startswith('question_') and value:
if key.endswith('_free'): if key.endswith('_free'):

View File

@@ -29,6 +29,10 @@
<hr> <hr>
{% include 'people/person/includes/answer_set_full.html' %}
<hr>
<div id="map" style="height: 800px; width: 100%"></div> <div id="map" style="height: 800px; width: 100%"></div>
<hr> <hr>

View File

@@ -33,10 +33,7 @@
{% csrf_token %} {% csrf_token %}
{% load bootstrap4 %} {% load bootstrap4 %}
{% bootstrap_form form exclude='latitude,longitude' %} {% bootstrap_form form %}
{% bootstrap_field form.latitude %}
{% bootstrap_field form.longitude %}
{% buttons %} {% buttons %}
<button class="btn btn-success" type="submit">Submit</button> <button class="btn btn-success" type="submit">Submit</button>

View File

@@ -1,6 +1,7 @@
import typing import typing
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils import timezone
from django.views.generic import CreateView, DetailView, ListView, UpdateView from django.views.generic import CreateView, DetailView, ListView, UpdateView
from people import forms, models from people import forms, models
@@ -30,6 +31,7 @@ class OrganisationDetailView(LoginRequiredMixin, DetailView):
"""Add map marker to context.""" """Add map marker to context."""
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['answer_set'] = self.object.current_answers
context['map_markers'] = [{ context['map_markers'] = [{
'name': self.object.name, 'name': self.object.name,
'lat': self.object.latitude, 'lat': self.object.latitude,
@@ -44,7 +46,7 @@ class OrganisationUpdateView(LoginRequiredMixin, UpdateView):
model = models.Organisation model = models.Organisation
context_object_name = 'organisation' context_object_name = 'organisation'
template_name = 'people/organisation/update.html' template_name = 'people/organisation/update.html'
form_class = forms.OrganisationForm form_class = forms.OrganisationAnswerSetForm
def get_context_data(self, def get_context_data(self,
**kwargs: typing.Any) -> typing.Dict[str, typing.Any]: **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -58,3 +60,37 @@ class OrganisationUpdateView(LoginRequiredMixin, UpdateView):
}] }]
return context return context
def get_initial(self) -> typing.Dict[str, typing.Any]:
try:
previous_answers = self.object.current_answers.as_dict()
except AttributeError:
previous_answers = {}
previous_answers.update({
'organisation_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 an Organisation, but expects an OrganisationAnswerSet."""
kwargs = super().get_form_kwargs()
kwargs.pop('instance')
return kwargs
def form_valid(self, form):
"""Mark any previous answer sets as replaced."""
response = super().form_valid(form)
now_date = timezone.now().date()
# Saving the form made self.object an OrganisationAnswerSet - so go up, then back down
# Shouldn't be more than one after initial updates after migration
for answer_set in self.object.organisation.answer_sets.exclude(
pk=self.object.pk):
answer_set.replaced_timestamp = now_date
answer_set.save()
return response