简体   繁体   中英

How to iterate over 2 variables in Django template

I have an app for some quiz with questions and choices. So I'm trying to render all this stuff to Django templates. In my views.py it looks like this

def choice(request):
    question_list = get_list_or_404(Question)
    page = get_object_or_404(Page, name='about')
    letters = ["A", "B", "C", "D", "E"]
    return render(request,
                  'qview/choice.html',
                  {
                    'question_list': question_list,
                    'page': page,
                    'letters': letters,
                   }
                  )

I have a list of questions and list with letters. All of that I'm sending as context to my template.

  {% if question_list %}
    <ul>
    {% for question in question_list %}
      <li><a href="#">{{question.question}}</a></li>
        <ul>
          {% for choice in question.choice_set.all %}
          <li>{{ choice.text }}</li>
          {% endfor %}
        </ul>
    {% endfor %}
    </ul>
  {% else %}
    <p>No questions available</p>
  {% endif %} 

So here I'm going through all of questions and all of choices connected to this question. But I can't get how I can also go through letters list? I was thinking about zip it all. But in view I have only questions not choices, so I can't zip to it.

So what else is possible here?

Django templates make some pretty handy loop builtins available. The one you want to use in this case is forloop.counter0 . Specifically, use it as an index for your letters list.

A custom template tag will help with making this more readable:

Create a custom template tag in templatetags/index.py :

from django import template
register = template.Library()

@register.filter
def index(indexable, i):
    return indexable[I]

Import the custom template tag at the top of your django template:

{% load index %}

Use the index tag inside your template to access the counter0 loop variable:

{% if question_list %}
<ul>
  {% for question in question_list %}
    <li><a href="#">{{question.question}}</a></li>
      <ul>
        {% for choice in question.choice_set.all %}
        <li>{{ letters|index:forloop.counter0 }}: {{ choice.text }}</li>
        {% endfor %}
      </ul>
  {% endfor %}
</ul>
{% else %}
  <p>No questions available</p>
{% endif %} 

Suggestion, it might be a better idea to "zip" them together and pass the zipped output to the template (you were already thinking about this -- good.) Templates should know as little as possible about your business logic and make as few assumptions as possible about your data structures.

So it'll be like A choice01, B choice 02 and so on

This can be solved by HTML. Use an ordered list .

        <ol type="A">
          {% for choice in question.choice_set.all %}
          <li>{{ choice.text }}</li>
          {% endfor %}
        </ol>

The above will produce a list like

A. choice 01
B. choice 02
...

Notice the dot ( . ) after the letter label/prefix. You could probably get rid of the dot with some CSS styling if it's considered not desirable.

cycle tag is perfect for such manner. It goes in for loop and takes first argument for first iteration, second for second and so on... If they are not enough, then it starts from the begininng.

    {% for choice in question.choice_set.all %}
        <li>{% cycle 'A' 'B' 'C' 'D' 'E' 'F' %}: {{ choice.text }}</li>
    {% endfor %}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM