0

I am creating a quiz/survey app.

  1. How may I use a form (such as a ModelForm) to display the options and a radio button for each question on the same page? (I have read the docs but seem currently incapable of producing an effective ModelForm.)
  2. How may I return all of the radio button selections to the view by clicking one submit button?

I have spent the day reading the docs, online articles, and as many SO answers as I could find. I suspect that there several factors that I have missed.

I have resorted to writing the page using template tags. I would like to know learn to use a django form properly.

models.py

from django.db import models
from django.contrib.auth.models import User


class Collection(models.Model):
    date = models.DateTimeField()

    def __str__(self):
        return 'Collection of questions'


class Question(models.Model):
    question_text = models.CharField(max_length=400)
    collection = models.ForeignKey(Collection, on_delete=models.CASCADE, default=None)
    date_published = models.DateTimeField('date published')

    @property
    def options(self):
        options = self.option_set.all()
        return options if options.exists() else 'No options for this question'

    def __str__(self):
        return self.question_text


class Option(models.Model):
    option_text = models.CharField(max_length=400)
    question = models.ForeignKey(Question, on_delete=models.CASCADE)

    def __str__(self):
        return f'{self.option_text}'


class Answer(models.Model):
    claim_reference_number = models.IntegerField()
    date_selected = models.DateTimeField('date selected')
    chosen_option = models.ForeignKey(Option, on_delete=models.CASCADE)
    collection = models.ForeignKey(Collection, on_delete=models.CASCADE)

    @property
    def question(self):
        return self.chosen_option.question

    def __str__(self):
        return f'{self.claim_reference_number} selected \'{self.chosen_option}\' in response to \'{self.question}\''

views.py

def new_assessment(request, reference_number):
    collection = Collection.objects.get(pk=1)
    context = {'collection': collection,
               'reference_number': reference_number,
               }
    return render(request, 'ad/templates/new_assessment.html', context)

Template

<h2>New survey</h2>
<form method="POST" action=''>
    {% csrf_token %}
    <div> reference_number = {{ reference_number }}</div>
    {% for question in collection.question_set.all %}
    <h5>{{ question.question_text }}</h5>
        {% for option in question.option_set.all %}
            <p><input type="radio" name="option for {{ question.pk }}" id="option{{ option.pk }}">
            <label for="option{{ option.pk }}">{{ option.option_text }}</label></p>
        {% endfor %}
    {% endfor %}
        <br>
    <button type="submit" class="save btn btn-default" value="selected">Save</button>
</form>

My current results using html and template tags are below. I would like to produce the same thing using a django form.

![Image]https://i.stack.imgur.com/J9Wm6.jpg

1 Answers1

0

Regarding:

1. How may I use a form (such as a ModelForm) to display the options and a radio button for each question on the same page?

I used a model formset factory with a custom model form. This is done by:

a) Creating a custom model form in forms.py (How to add a custom field in django model form?). To achieve what I wanted, this involved using the Meta class: to define the choices as being in the foreign key of the options related to the particular question; and to add a RadioSelect widget for each option.

b) Creating a model formset. This involves building the model formset with a model formset factory and your custom model form (https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/)

c) Using the view to pass the model formset from forms.py (where I created the modelformset and custom form) to the template.

2. How may I return all of the radio button selections to the view by clicking one submit button?

Pressing the submit button posts the completed formset back to views. Once it arrives, iterate over the formset data (Django accessing formset data). Create and save the appropriate model records in the database.