I have a requirement to create a survey form. Different types of users will have different set of questions to answer in the survey.
models.py
from django.contrib.auth.models import Group, User
from django.db import models
ANSWER_CHOICES = (
('0', 'No'),
('1', 'Yes')
)
class Survey(models.Model):
name = models.CharField(max_length=100)
group = models.ForeignKey(Group)
def __str__(self):
return self.name
class Feature(models.Model):
name = models.CharField(max_length=150)
survey = models.ForeignKey(Survey)
def __str__(self):
return self.name
class Rating(models.Model):
rating = models.IntegerField(choices=ANSWER_CHOICES)
feature = models.ForeignKey(Feature)
rating_for = models.ForeignKey(User, related_name='rated_user')
rating_by = models.ForeignKey(User, related_name='rated_by')
def __str__(self):
return str.format("%s - %s", self.feature, self.rating)
The answer(rating) for each question(feature) is either a yes or a no represent by radio buttons. Once the user submits the form, its saves the answers in the rating table.
What is the django way of achieving this?
Thanks
forms.py
from django import forms
from django.forms import modelformset_factory, TextInput
from survey.models import Rating, Feature
class FeatureForm(forms.ModelForm):
class Meta:
model = Feature
class RatingForm(forms.ModelForm):
class Meta:
model = Rating
FeatureFormSetBase = modelformset_factory(Feature, extra=0,
widgets={'name': TextInput(attrs={'readonly': True, })}
)
class FeatureFormSet(FeatureFormSetBase):
def add_fields(self, form, index):
super(FeatureFormSet, self).add_fields(form, index)
form.fields['is_checked'] = forms.BooleanField(required=False)
survey.html
<form action="." method="post" accept-charset="utf-8">
<ul class="list-group">
{% for form in formset.forms %}
<li class="list-group-item">
<div class="hidden"> {{ form.survey }}</div>
<span> {{ form.name }} </span>
<span> {{ form.id }} </span>
<span> {{ form.is_checked }} </span>
</li>
{% endfor %}
</ul>
<p>
{{ formset.management_form }}
{% csrf_token %}
<button type="submit" name="action" value="save" class="btn btn-success">SAVE</button>
</p>
</form>
That's the code I have and it works now but I am not sure if its the best way to solve this problem? I have a lot of code in views.py to parse the post data...is there a cleaner way to achieve this?
view.py
def questionnaire(request):
q = Feature.objects.filter(survey__group=request.user.groups.all()[0]).select_related('survey')
if request.method == 'POST':
action = request.POST.get('action')
formset = FeatureFormSet(request.POST, queryset=q)
if formset.is_valid():
# iterate over all forms in the formset
for form in formset.forms:
if action == u'save':
answer = form.cleaned_data.get('is_checked')
print("Saving answer...")
rating = Rating()
rating.rating = answer
rating.feature = form.cleaned_data.get('id')
rating.rating_for = request.user
rating.rating_by = request.user
rating.save()
redirect('useraccount_dashboard')
else:
formset = FeatureFormSet(queryset=q)
return render_to_response('account_survey.html', {'formset': formset}, context_instance=RequestContext(request))
UPDATED views.py
def questionnaire(request, instance_id):
try:
instance = SurveyInstance.objects.get(pk=instance_id, completed=False)
except SurveyInstance.DoesNotExist:
raise Http404
if instance.rating_by != request.user:
return HttpResponse('Unauthorized', status=401)
q = Feature.objects.filter(survey=instance.survey)
if request.method == 'POST':
action = request.POST.get('action')
formset = FeatureFormSet(request.POST, queryset=q)
if formset.is_valid():
# iterate over all forms in the formset
for form in formset.forms:
if action == u'save':
answer = form.cleaned_data.get('is_checked')
print("Saving answer...")
rating = Rating()
rating.rating = answer
rating.feature = form.cleaned_data.get('id')
rating.survey_instance = instance
rating.save()
instance.completed = True
instance.save()
messages.add_message(request, messages.INFO, 'Thank you for your feedback.')
return redirect('useraccount_dashboard')
else:
formset = FeatureFormSet(queryset=q)
return render_to_response('account_survey.html', {'formset': formset}, context_instance=RequestContext(request))
Try using form.save()
instead of creating the Rating
object, filling in it's fields and then saving.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With