From 94b2ee9d707d623e23a94ae0707fe0521bd877f2 Mon Sep 17 00:00:00 2001 From: James Graham Date: Fri, 22 Jan 2021 17:15:18 +0000 Subject: [PATCH] feat: allow free form text answers see #52 --- people/forms.py | 27 +++++++++++++++++-- .../0031_question_allow_free_text.py | 23 ++++++++++++++++ people/models/__init__.py | 1 + people/models/question.py | 10 +++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 people/migrations/0031_question_allow_free_text.py diff --git a/people/forms.py b/people/forms.py index 607214f..16e50f2 100644 --- a/people/forms.py +++ b/people/forms.py @@ -46,9 +46,10 @@ class RelationshipForm(forms.Form): class DynamicAnswerSetBase(forms.Form): field_class = forms.ModelChoiceField - field_widget = None field_required = True - question_model = None + field_widget: typing.Optional[typing.Type[forms.Widget]] = None + question_model: typing.Type[models.Question] + answer_model: typing.Type[models.QuestionChoice] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -72,6 +73,11 @@ class DynamicAnswerSetBase(forms.Form): initial=initial.get(field_name, None)) self.fields[field_name] = field + if question.allow_free_text: + free_field = forms.CharField(label=f'{question} free text', + required=False) + self.fields[f'{field_name}_free'] = free_field + class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase): """Form for variable person attributes. @@ -104,6 +110,7 @@ class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase): } question_model = models.PersonQuestion + answer_model = models.PersonQuestionChoice def save(self, commit=True) -> models.PersonAnswerSet: # Save Relationship model @@ -116,6 +123,13 @@ class PersonAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase): # Save answers to relationship 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) @@ -139,6 +153,7 @@ class RelationshipAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase): ] question_model = models.RelationshipQuestion + answer_model = models.RelationshipQuestionChoice def save(self, commit=True) -> models.RelationshipAnswerSet: # Save Relationship model @@ -148,6 +163,13 @@ class RelationshipAnswerSetForm(forms.ModelForm, DynamicAnswerSetBase): # Save answers to relationship 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) @@ -166,6 +188,7 @@ class NetworkFilterForm(DynamicAnswerSetBase): field_widget = Select2MultipleWidget field_required = False question_model = models.RelationshipQuestion + answer_model = models.RelationshipQuestionChoice def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/people/migrations/0031_question_allow_free_text.py b/people/migrations/0031_question_allow_free_text.py new file mode 100644 index 0000000..a1dfaff --- /dev/null +++ b/people/migrations/0031_question_allow_free_text.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.10 on 2021-01-20 13:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('people', '0030_user_consent_given'), + ] + + operations = [ + migrations.AddField( + model_name='personquestion', + name='allow_free_text', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='relationshipquestion', + name='allow_free_text', + field=models.BooleanField(default=False), + ), + ] diff --git a/people/models/__init__.py b/people/models/__init__.py index e8bc10e..f3a1059 100644 --- a/people/models/__init__.py +++ b/people/models/__init__.py @@ -1,2 +1,3 @@ from .person import * +from .question import * from .relationship import * diff --git a/people/models/question.py b/people/models/question.py index 7379fb3..7948640 100644 --- a/people/models/question.py +++ b/people/models/question.py @@ -4,6 +4,11 @@ import typing from django.db import models from django.utils.text import slugify +__all__ = [ + 'Question', + 'QuestionChoice', +] + class Question(models.Model): """Questions from which a survey form can be created.""" @@ -27,6 +32,11 @@ class Question(models.Model): blank=False, null=False) + #: Should people be able to add their own answers? + allow_free_text = models.BooleanField(default=False, + blank=False, + null=False) + #: Position of this question in the list order = models.SmallIntegerField(default=0, blank=False, null=False)