Django- link answer choice to question and survey

Issue

I am trying to create a number of surveys in Django and put them in a survey index page. I have run into an issue: Up until now, all of my surveys had questions which had the same set of answer choices, so in my Django models I linked the answers only to the survey because it was the easiest for me and it was working. Now I have to add a new survey where each question has a different set of answers choices (if you are curious, this is the survey: https://www.fresno.ucsf.edu/pediatrics/downloads/edinburghscale.pdf). My problem is that for this new survey I am now getting every possible answer choice in the whole survey for each question.

How can I link the answer choices to the question so that I will only see the choices for the corresponding question? Yes, I have read the Django polls tutorial and have tried requesting the question_id, but then I got an error along the lines of "missing question_id" so I went back to my original code. I think the right approach would be to link the answer choices to both the question and the survey, but not sure.

Here is my model:

class Questionnaire(models.Model): 
name = models.CharField(max_length=255) 
text = models.CharField(max_length=200)
# def get_absolute_url(self):
    # return reverse('questionnaire-detail', args=[str(self.id)])

def __str__(self):
    return self.name
class Question(models.Model):
    text = models.CharField(max_length=200)
    questionnaire = models.ForeignKey(Questionnaire, on_delete=models.CASCADE, related_name='questions')
    def __str__(self):
        return self.text

class Answer(models.Model):
    question = models.ForeignKey(Question, models.SET_NULL, blank=True, null=True, related_name='answerlist')
    questionnaire = models.ForeignKey(Questionnaire, on_delete=models.CASCADE, related_name='answers', default='')
    text = models.CharField(max_length=200)
    image = models.CharField(null=True, max_length=20)
    image_location = models.CharField(null=True, max_length=20)
    
    def __str__(self):
        return self.text

Here is my views:


    ResponseFormSet = modelformset_factory(Response, form=ResponseForm, extra=0)
    if request.method == 'POST':
        formset = ResponseFormSet(request.POST or None, request.FILES, form_kwargs={'user': request.user})
        if formset.is_valid():
  
            print("Formset is valid")
            formset.save()
            return HttpResponseRedirect(reverse ('questionnaires:questionnaire_index'))
   
        else:
            print("Formset is NOT valid")
            print(formset.errors)
            print(formset.non_form_errors())
        

    questionnaire = Questionnaire.objects.get(id=questionnaire_id)
    questions = Question.objects.filter(questionnaire_id=questionnaire_id)
    answers = Answer.objects.filter(questionnaire_id=questionnaire_id)
    


    return render(request, 'questionnaires/questionnaire_lec.html', {
        'questions': questions,
        'answers': answers,
        'questionnaire': questionnaire,
        })

And my HTML:

<form method="post" action="{{ request.url }}">
  {% csrf_token %}

  <legend><h2>{{ questionnaire.text }}</h2></legend>
  <br>

  {% for question in questions %}
      <h3>{{question.text}}</h3> 
  
      <label hidden="" for="id_form-{{ forloop.counter0 }}-question">Question:</label>
      <select hidden="" name="form-{{ forloop.counter0 }}-question" id="id_form-{{ forloop.counter0 }}-question">
          <option value="{{question.id}}" selected="">{{question.text}}</option>
      </select>

      <!-- <label for="id_form-{{ forloop.counter0 }}-answer">Answer:</label> -->
      
      
      {% for answer in answers %}
          <label for="id_form-{{ forloop.counter0 }}-answer">
              <input type="radio" name="form-{{ forloop.parentloop.counter0 }}-answer" id="id_form-{{ forloop.counter0 }}-answer" value="{{answer.id}}">
              {{answer.text}}
          </label> <br>
      {% endfor %}


      <input type="hidden" name="form-{{ forloop.counter0 }}-id" value="{{ forloop.counter }}" id="id_form-{{ forloop.counter0 }}-id">
         
      <input type="hidden" name="form-TOTAL_FORMS" value="{{questions|length}}" id="id_form-TOTAL_FORMS" />
      <input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" />
      <input type="hidden" name="form-MAX_NUM_FORMS" value="{{questions|length}}" id="id_form-MAX_NUM_FORMS" />

  {% endfor %}

  <br />
  <br />
  <input type="submit" value="Submit">
</form>
{% endif %}
{% endblock %}

Thank you in advance for any help!

Solution

You should use:

{% for answer in question.answerlist.all %}
    …
{% endfor %}

There is no need to pass a QuerySet of Answers to the template.

Answered By – Willem Van Onsem

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published