I am building a survey tool and I'm wondering how would I continue with this or if my current solution is even the proper way to do it.
from django.shortcuts import render
from .models import Questionnaire, Question, Answer
def index(request):
all_questionnaires = Questionnaire.objects.all()
all_questions = Question.objects.all()
return render(request, 'questions/index.html', locals())
def questionnaire_detail(request, questionnaire_id):
questionnaire = Questionnaire.objects.get(id=questionnaire_id)
questions = Question.objects.filter(questionnaire=questionnaire)
return render(request, 'questions/questionnaire.html',
{'questionnaire': questionnaire, 'questions': questions})
def calculate(request):
if request.method == 'POST':
pass
from django.db import models
MC = 'MC'
CN = 'CN'
TX = 'TX'
CATEGORY = (
(MC, 'Multichoice'),
(CN, 'Choose N'),
(TX, 'Text'),
)
VALYK = '1'
VALKA = '2'
VALKO = '3'
VALNE = '4'
VALVI = '5'
MULTICHOICE = (
(VALYK, 'Least'),
(VALKA, 'Less than average'),
(VALKO, 'Average'),
(VALNE, 'More than average'),
(VALVI, 'Most'),
)
class Questionnaire(models.Model):
questionnaire_name = models.CharField(max_length=100,
verbose_name="Questionnaire",
null=False,
default=None,
blank=False)
def __str__(self):
return self.questionnaire_name
class Question(models.Model):
questionnaire = models.ManyToManyField(Questionnaire)
question_text = models.CharField(max_length=200,
verbose_name="Questionnaire name",
null=True,
default=None,
blank=True)
question_category = models.CharField(max_length=2,
verbose_name="Question category",
null=False,
choices=CATEGORY,
default=None,
blank=False)
def __str__(self):
return self.question_text
class Answer(models.Model):
question = models.ForeignKey(Question)
class MultiChoiceAnswer(Answer):
answer = models.IntegerField(choices=MULTICHOICE)
def __str__(self):
return self.answer
{% extends "questions/base.html" %}
{% block title_html %}
Questionnaire
{% endblock %}
{% block h1 %}
Questionnaire
{% endblock %}
{% block content %}
{% if questions|length > 0 %}
<form action="{% url "questions:calculate" %}" method="post">
{% csrf_token %}
{% for question in questions %}
{{ question.question_text }}<br>
{% if question.question_category == "MC" %}
<input type="radio" name="{{ question.id }}" value="1"> 1<br>
<input type="radio" name="{{ question.id }}" value="2"> 2<br>
<input type="radio" name="{{ question.id }}" value="3"> 3<br>
<input type="radio" name="{{ question.id }}" value="4"> 4<br>
<input type="radio" name="{{ question.id }}" value="5"> 5<br>
{% elif question.question_category == "CN" %}
<input type="checkbox" name="{{ question.id }}" value="a">a<br>
<input type="checkbox" name="{{ question.id }}" value="b">b<br>
{% elif question.question_category == "TX" %}
<textarea rows="4" cols="50" name="{{ question.id }}">Test</textarea><br>
{% endif %}
{% endfor %}
<input type="submit" value="Send" />
</form>
{% else %}
<span>No questions</span>
{% endif %}
{% endblock %}
This is the solution I ended up with. Edited it a bit to be more generic.
In the view there is checking if the form was loaded or submitted. If it was submitted, then check the validity of all of the forms. As there are multiple forms they are then made as formsets.
View
def answerpage(request, questionnaire_pk):
AnswerFormSet = formset_factory(AnswerForm, extra=0)
questions = Question.objects.filter(questionnaire=questionnaire_pk)
qname = Questionnaire.objects.get(id=questionnaire_pk)
if request.method == 'POST':
answer_formset = AnswerFormSet(request.POST)
if answer_formset.is_valid():
for answer_form in answer_formset:
if answer_form.is_valid():
instance = answer_form.save(commit=False)
instance.fieldValue = answer_form.cleaned_data.get('fieldValue')
instance.save()
return redirect('main:calcs')
else:
return redirect('main:home')
else:
quest_id = request.session.get('questionnaire_key', defaultValue)
question_data = [{'question': question,
'questionnaire_key': quest_id} for question in questions]
answer_formset = AnswerFormSet(initial=question_data)
combined = zip(questions, answer_formset)
context = {
'combined': combined,
'answer_formset': answer_formset,
'qname': qname,
}
return render(request, 'main/questionnaire.html', context)
The form is a modelform with the default widgets overwritten.
Form
class AnswerForm(forms.ModelForm):
class Meta:
model = QuestionAnswer
exclude = ['']
widgets = {
'field1': RadioSelect(choices=CHOICES, attrs={'required': 'True'}),
'field2': HiddenInput,
}
Webpage renders the values from the view in to a table. Management_form is needed to handle the formset values correctly.
Webpage
{% extends "main/base.html" %}
{% load static %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/survey.css' %}">
<h1>{{ qname.questionnaire_text }}</h1>
<h2>{{ qname.description }}</h2>
<form method="post">{% csrf_token %}
{{ answer_formset.management_form }}
<table>
{% for question, form in combined %}
<tr><td style="width:65%">{{ question }}{{ question.question_type }}</td><td style="width:35%">{{ form.business_id }}{{ form.question }}{{ form.questionnaire_key }}{{ form.answer_text }}</td></tr>
{% endfor %}
</table>
<div class="buttonHolder">
<input type="submit" value="Save" id="next_button"/>
</div>
</form>
{% endblock %}