fix: use prev answers as initial for relationships

Resolves #65
This commit is contained in:
James Graham
2021-03-10 12:38:49 +00:00
parent 6f72244331
commit 75bc12de57
8 changed files with 83 additions and 93 deletions

View File

@@ -45,7 +45,6 @@ class DynamicAnswerSetBase(forms.Form):
def __init__(self, *args, as_filters: bool = False, **kwargs): def __init__(self, *args, as_filters: bool = False, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
initial = kwargs.get('initial', {})
field_order = [] field_order = []
for question in self.question_model.objects.all(): for question in self.question_model.objects.all():
@@ -77,7 +76,7 @@ class DynamicAnswerSetBase(forms.Form):
widget=field_widget, widget=field_widget,
required=(self.field_required required=(self.field_required
and not question.allow_free_text), and not question.allow_free_text),
initial=initial.get(field_name, None), initial=self.initial.get(field_name, None),
help_text=question.help_text if not as_filters else '') help_text=question.help_text if not as_filters else '')
self.fields[field_name] = field self.fields[field_name] = field
field_order.append(field_name) field_order.append(field_name)

View File

@@ -208,20 +208,8 @@ class PersonAnswerSet(AnswerSet):
if field.attname not in exclude_fields if field.attname not in exclude_fields
} }
for answer in self.question_answers.all(): # Add answers to dynamic questions
question = answer.question return super().as_dict(answers=answers)
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): def get_absolute_url(self):
return self.person.get_absolute_url() return self.person.get_absolute_url()

View File

@@ -144,3 +144,23 @@ class AnswerSet(models.Model):
replaced_timestamp = models.DateTimeField(blank=True, replaced_timestamp = models.DateTimeField(blank=True,
null=True, null=True,
editable=False) editable=False)
def as_dict(self, answers: typing.Optional[typing.Dict[str, typing.Any]] = None):
"""Get the answers from this set as a dictionary for use in Form.initial."""
if answers is None:
answers = {}
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

View File

@@ -40,7 +40,7 @@
<hr> <hr>
<a class="btn btn-success" <a class="btn btn-success"
href="{% url 'people:organisation.relationship.update' relationship_pk=relationship.pk %}">Update</a> href="{% url 'people:organisation.relationship.update' pk=relationship.pk %}">Update</a>
{% with relationship.current_answers as answer_set %} {% with relationship.current_answers as answer_set %}
<table class="table table-borderless"> <table class="table table-borderless">

View File

@@ -20,7 +20,7 @@
<a class="btn btn-sm btn-info" <a class="btn btn-sm btn-info"
href="{% url 'people:relationship.detail' pk=relationship.pk %}">Relationship Detail</a> href="{% url 'people:relationship.detail' pk=relationship.pk %}">Relationship Detail</a>
<a class="btn btn-sm btn-success" <a class="btn btn-sm btn-success"
href="{% url 'people:relationship.update' relationship_pk=relationship.pk %}">Update</a> href="{% url 'people:relationship.update' pk=relationship.pk %}">Update</a>
</td> </td>
</tr> </tr>
@@ -55,7 +55,7 @@
<a class="btn btn-sm btn-info" <a class="btn btn-sm btn-info"
href="{% url 'people:organisation.relationship.detail' pk=relationship.pk %}">Relationship Detail</a> href="{% url 'people:organisation.relationship.detail' pk=relationship.pk %}">Relationship Detail</a>
<a class="btn btn-sm btn-success" <a class="btn btn-sm btn-success"
href="{% url 'people:organisation.relationship.update' relationship_pk=relationship.pk %}">Update</a> href="{% url 'people:organisation.relationship.update' pk=relationship.pk %}">Update</a>
</td> </td>
</tr> </tr>

View File

@@ -46,7 +46,7 @@
<hr> <hr>
<a class="btn btn-success" <a class="btn btn-success"
href="{% url 'people:relationship.update' relationship_pk=relationship.pk %}">Update</a> href="{% url 'people:relationship.update' pk=relationship.pk %}">Update</a>
{% with relationship.current_answers as answer_set %} {% with relationship.current_answers as answer_set %}
<table class="table table-borderless"> <table class="table table-borderless">

View File

@@ -56,7 +56,7 @@ urlpatterns = [
views.relationship.RelationshipDetailView.as_view(), views.relationship.RelationshipDetailView.as_view(),
name='relationship.detail'), name='relationship.detail'),
path('relationships/<int:relationship_pk>/update', path('relationships/<int:pk>/update',
views.relationship.RelationshipUpdateView.as_view(), views.relationship.RelationshipUpdateView.as_view(),
name='relationship.update'), name='relationship.update'),
@@ -70,7 +70,7 @@ urlpatterns = [
views.relationship.OrganisationRelationshipDetailView.as_view(), views.relationship.OrganisationRelationshipDetailView.as_view(),
name='organisation.relationship.detail'), name='organisation.relationship.detail'),
path('organisation-relationships/<int:relationship_pk>/update', path('organisation-relationships/<int:pk>/update',
views.relationship.OrganisationRelationshipUpdateView.as_view(), views.relationship.OrganisationRelationshipUpdateView.as_view(),
name='organisation.relationship.update'), name='organisation.relationship.update'),

View File

@@ -5,7 +5,7 @@ import typing
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.views.generic import CreateView, DetailView, RedirectView from django.views.generic import DetailView, RedirectView, UpdateView
from people import forms, models, permissions from people import forms, models, permissions
@@ -31,73 +31,65 @@ class RelationshipCreateView(LoginRequiredMixin, RedirectView):
source=self.request.user.person, target=target) source=self.request.user.person, target=target)
return reverse('people:relationship.update', return reverse('people:relationship.update',
kwargs={'relationship_pk': relationship.pk}) kwargs={'pk': relationship.pk})
class RelationshipUpdateView(permissions.UserIsLinkedPersonMixin, CreateView): class RelationshipUpdateView(permissions.UserIsLinkedPersonMixin, UpdateView):
""" """View for updating the details of a relationship.
View for updating the details of a relationship.
Creates a new :class:`RelationshipAnswerSet` for the :class:`Relationship`. Creates a new :class:`RelationshipAnswerSet` for the :class:`Relationship`.
Displays / processes a form containing the :class:`RelationshipQuestion`s. Displays / processes a form containing the :class:`RelationshipQuestion`s.
""" """
model = models.RelationshipAnswerSet model = models.Relationship
context_object_name = 'relationship'
template_name = 'people/relationship/update.html' template_name = 'people/relationship/update.html'
form_class = forms.RelationshipAnswerSetForm form_class = forms.RelationshipAnswerSetForm
def get_test_person(self) -> models.Person: def get_test_person(self) -> models.Person:
""" """Get the person instance which should be used for access control checks."""
Get the person instance which should be used for access control checks. return self.object.source
"""
relationship = models.Relationship.objects.get(
pk=self.kwargs.get('relationship_pk'))
return relationship.source
def get(self, request, *args, **kwargs):
self.relationship = models.Relationship.objects.get(
pk=self.kwargs.get('relationship_pk'))
self.person = self.relationship.source
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.relationship = models.Relationship.objects.get(
pk=self.kwargs.get('relationship_pk'))
self.person = self.relationship.source
return super().post(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['person'] = self.object.source
context['person'] = self.person
context['relationship'] = self.relationship
return context return context
def get_initial(self): def get_initial(self):
initial = super().get_initial() try:
previous_answers = self.object.current_answers.as_dict()
initial['relationship'] = self.relationship except AttributeError:
previous_answers = {}
return initial previous_answers.update({
'relationship': self.object,
})
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."""
kwargs = super().get_form_kwargs()
kwargs.pop('instance')
return kwargs
def form_valid(self, form): def form_valid(self, form):
""" """Mark any previous answer sets as replaced."""
Mark any previous answer sets as replaced.
"""
response = super().form_valid(form) response = super().form_valid(form)
now_date = timezone.now().date() now_date = timezone.now().date()
# Shouldn't be more than one after initial updates after migration # Shouldn't be more than one after initial updates after migration
for answer_set in self.relationship.answer_sets.exclude( for answer_set in self.object.relationship.answer_sets.exclude(
pk=self.object.pk): pk=self.object.pk):
answer_set.replaced_timestamp = now_date answer_set.replaced_timestamp = now_date
answer_set.save() answer_set.save()
return response return response
def get_success_url(self) -> str:
return self.object.get_absolute_url()
class OrganisationRelationshipDetailView(permissions.UserIsLinkedPersonMixin, class OrganisationRelationshipDetailView(permissions.UserIsLinkedPersonMixin,
DetailView): DetailView):
@@ -121,59 +113,50 @@ class OrganisationRelationshipCreateView(LoginRequiredMixin, RedirectView):
source=self.request.user.person, target=target) source=self.request.user.person, target=target)
return reverse('people:organisation.relationship.update', return reverse('people:organisation.relationship.update',
kwargs={'relationship_pk': relationship.pk}) kwargs={'pk': relationship.pk})
class OrganisationRelationshipUpdateView(permissions.UserIsLinkedPersonMixin, class OrganisationRelationshipUpdateView(permissions.UserIsLinkedPersonMixin,
CreateView): UpdateView):
""" """View for updating the details of a Organisationrelationship.
View for updating the details of a Organisationrelationship.
Creates a new :class:`OrganisationRelationshipAnswerSet` for the :class:`OrganisationRelationship`. Creates a new :class:`OrganisationRelationshipAnswerSet` for the :class:`OrganisationRelationship`.
Displays / processes a form containing the :class:`OrganisationRelationshipQuestion`s. Displays / processes a form containing the :class:`OrganisationRelationshipQuestion`s.
""" """
model = models.OrganisationRelationshipAnswerSet model = models.OrganisationRelationship
context_object_name = 'relationship'
template_name = 'people/relationship/update.html' template_name = 'people/relationship/update.html'
form_class = forms.OrganisationRelationshipAnswerSetForm form_class = forms.OrganisationRelationshipAnswerSetForm
def get_test_person(self) -> models.Person: def get_test_person(self) -> models.Person:
""" """Get the person instance which should be used for access control checks."""
Get the person instance which should be used for access control checks. return self.object.source
"""
relationship = models.OrganisationRelationship.objects.get(
pk=self.kwargs.get('relationship_pk'))
return relationship.source def get_initial(self):
try:
previous_answers = self.object.current_answers.as_dict()
def get(self, request, *args, **kwargs): except AttributeError:
self.relationship = models.OrganisationRelationship.objects.get( previous_answers = {}
pk=self.kwargs.get('relationship_pk'))
self.person = self.relationship.source
return super().get(request, *args, **kwargs) previous_answers.update({
'relationship': self.object,
})
def post(self, request, *args, **kwargs): return previous_answers
self.relationship = models.OrganisationRelationship.objects.get(
pk=self.kwargs.get('relationship_pk'))
self.person = self.relationship.source
return super().post(request, *args, **kwargs) def get_form_kwargs(self) -> typing.Dict[str, typing.Any]:
"""Remove instance from form kwargs as it's a person, but expects a PersonAnswerSet."""
kwargs = super().get_form_kwargs()
kwargs.pop('instance')
return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['person'] = self.object.source
context['person'] = self.person
context['relationship'] = self.relationship
return context return context
def get_initial(self):
initial = super().get_initial()
initial['relationship'] = self.relationship
return initial
def form_valid(self, form): def form_valid(self, form):
""" """
Mark any previous answer sets as replaced. Mark any previous answer sets as replaced.
@@ -182,7 +165,7 @@ class OrganisationRelationshipUpdateView(permissions.UserIsLinkedPersonMixin,
now_date = timezone.now().date() now_date = timezone.now().date()
# Shouldn't be more than one after initial updates after migration # Shouldn't be more than one after initial updates after migration
for answer_set in self.relationship.answer_sets.exclude( for answer_set in self.object.relationship.answer_sets.exclude(
pk=self.object.pk): pk=self.object.pk):
answer_set.replaced_timestamp = now_date answer_set.replaced_timestamp = now_date
answer_set.save() answer_set.save()