Trying to create a generic HTML template that renders a set of questions under topic headings based on context from views.py

I have several areas, i.e. Leadership, operations, etc., each of which has a set of topics and questions associated with it. Leadership, for example, has 3 topics, each with a different set and number of questions.

I am trying to create a general questions.html template where the views.py can then fit with the specific area, topics, questions, etc. for that area. I provide the topics, separate question sets for each topic via context when rendering the page for that area.

I am trying to avoid hardcoding each page by looping through each topic and using the question set for that topic.

I tested the code by hardcoding 1 question set and seeing if the table render properly, and it does except of course the questions are repeated under each topic.

However, when I set the outer loop to loop through the topics with each unique questions set using variables, none of the questions appear. The page just renders the topics with no errors.

Here is the code snippet that works but reuses the questions:

  <tbody>
{% for m in categories %}
    <td colspan="7">{{ m }}</td>
    
        {% for key, value in questions1.items %}
        <tr>
            <td class="question">{{ value }} </td>
                {% for n in nchoices %}
                    {% if n == 0 %} 
                    <td>
                    
                        <input name={{ key }} type="radio" value={{ n }}  id="{{ key }}_{{n}}"/> Not Sure
                
                    </td>
                    {% else %}
                    <td>
                    
                    <input name={{ key }} type="radio" value={{ n }}  id="{{ key }}_{{n}}"/>{{ n }}
            
                    </td>
                    {% endif%}
                {% endfor %}
        </tr>
        {% endfor %}
{% endfor %}
</table>

<h4>Enter any comments about your responses to the questions</h4>
<textarea name="{{ textname }}"></textarea>

<input type="submit">

views.py snippet (edited to remove non essential code):

def test(request):
        questions1 = {"L_Q1": "Conducts annual risk assessments and identifies key risks and mitigation actions"}
        
        questions2 =  {"L_Q4":"Provides the necessary resources for accomplishing business continuity objectives"}
        
        questions3 =  {"L_Q8": "Conduct annual test of business continuity plans"}
        
        nchoices = [0,1,2,3,4,5]

        categories = ["Risk Assessment and Planning", "Oversight", "Execution and Improvement"]
        
        questions = ["questions1","questions2","questions3"]

        textname= ["L_Text"]
        
        context = {
            "questions": questions,
            "questions1": questions1,
            "questions2": questions2,
            "questions3": questions3,
            "categories": categories,
            "nchoices": nchoices,
            "textname": textname
        }

        if request.method == "POST":
            return render(request, "leadershipresults.html", context)
        else:

            return render(request, "questions.html", context)

I tried adding loops inside the outer loop to select each question set but that's when it fails to render the questions, for example:

{% for m in categories %}
    <td colspan="7">{{ m }}</td>
    {% for x in questions %}
            {% for key, value in x.items %}
            <tr>
                <td class="question">{{ value }} </td>
                    {% for n in nchoices %}
                        {% if n == 0 %} 
                        <td>
                        
                            <input name={{ key }} type="radio" value={{ n }}  id="{{ key }}_{{n}}"/> Not Sure
                    
                        </td>
                        {% else %}
                        <td>
                        
                        <input name={{ key }} type="radio" value={{ n }}  id="{{ key }}_{{n}}"/>{{ n }}
                
                        </td>
                        {% endif%}
                    {% endfor %}
            </tr>
            {% endfor %}
        {% endfor %}
{% endfor %}

Is it possible to use a variable to identify which list to use select the proper question set?

I renamed the django models to follow PEP guides.See here

# type: ignore
from django.db import models


class Topic(models.Model):
    name = models.CharField(max_length=20)
   

    def __str__(self):
        return f"{self.name}"


class Question(models.Model):
    question = models.CharField(max_length=200)
    name = models.CharField(max_length=20)  # THis is probably useless

    topic = models.ForeignKey(
        Topic, on_delete=models.CASCADE
    )  # Django will store this as topic_id on database

    def __str__(self):
        return f"{self.name} is question {self.question}"


class Answer(models.Model):
    value = models.IntegerField()
    name = models.CharField(max_length=20)
    # q_id = models.CharField(max_length=10, default="XX")  # USed foreignkey instead
    question = models.ForeignKey(Question, on_delete=models.CASCADE)

    def __str__(self):
        return f"{self.question} value is {self.value}"


class Comment(models.Model):
    name = models.CharField(max_length=20)
    comments = models.CharField(max_length=1000, default="No comment")
    question = models.ForeignKey(
        Question, on_delete=models.CASCADE
    )  # Use One to one if a question has one answer

    def __str__(self):
        return f"{self.name} comments are {self.comments}"

The simple way to get the Questions and respective topics would be

questions = Question.objects.select_related('topic').all()
#Then create a dict
from collections import defaultdict
questions_by_topic = defaultdict(list)#If not topic in dict then it will create it with empty list as value
for question in questions:
    questions_by_topic[question.topic].append(question.question)

#You can then use the dict in html as so
for topic, questions in questions_by_topic.items():
    print(f"Topic: {topic.name}")
    for question in questions:
        print(f" - {question}")
Back to Top