Python Flask Basics Character Builder Loop Nested Items

Nested loops in Flask - how to iterate and make nested lists.

This is my code: Quiz says that there are 0 <li>

<ul class="teachers"> {% for teacher in teachers %} <li> <h2> {{ teacher.name }} </h2> <ul> {% for x in teacher.name.courses %} <li> {{ x }} </li> {% endfor %} </ul> </li> {% endfor %} </ul>

flask_app.py
from flask import Flask, render_template

from teachers import TEACHERS

app = Flask(__name__)


@app.route('/')
def index():
    return render_template("teachers.html", teachers=TEACHERS)
templates/teachers.html
<ul class="teachers">
  {% for teacher in teachers %}
  <li> <h2> {{ teacher.name }} </h2> 
  <ul>
    {% for x in teacher.name.courses %}
    <li> {{ x }} </li>
  {% endfor %}
  </ul>
  </li>
    {% endfor %}
</ul>
Chen Wang
Chen Wang
7,371 Points

How come we can use the expression of

teacher.name

teachers is a dictionary, right? Therefore, teacher should be a key-value pair (item). if it is something like { "name": "Tom"}, them we can use

teacher['name']

Can anyone just give me an simple example of the "teachers" dictionary.

I'm so confused.

Chris Freeman
Chris Freeman
Treehouse Moderator 59,905 Points

Chen Wang, in short, yes you can. According to the jinja template docs:

The following lines do the same thing:

{{ foo.bar }}
{{ foo['bar'] }}

Implementation

For the sake of convenience, foo.bar in Jinja2 does the following things on the Python layer:

  • check for an attribute called bar on foo (getattr(foo, 'bar'))
  • if there is not, check for an item 'bar' in foo (foo.getitem('bar'))
  • if there is not, return an undefined object.

foo['bar'] works mostly the same with a small difference in sequence:

  • check for an item 'bar' in foo. (foo.getitem('bar'))
  • if there is not, check for an attribute called bar on foo. (getattr(foo, 'bar'))
  • if there is not, return an undefined object.

This is important if an object has an item and attribute with the same name. Additionally, the attr() filter only looks up attributes.

2 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 59,905 Points

Hi Kacper Wikieł, I see two fixes for your code. First, the new <code><ul></code> needs the class attribute with the value 'courses'. Second, courses are an attribute of teachers, so the for-loop needs to be for x in teacher.courses

My full solution is below.

Taking the loop nested items Challenge Task 2 of 2:

Now add a new <code><ul></code> inside of the <code><li></code> with a class of "courses". Inside this <code><ul></code> loop through the teacher's 'courses' key, creating an <code><li></code> for each course and printing the course.

<ul class="teachers">
  {% for teacher in teachers %}
  <li>
    <h2>{{ teacher.name }} </h2>
    <!--  New ul with class of 'courses' -->
    <ul class='courses'>
      {% for course in teacher.courses %}
      <li>{{ course }}</li>
      {% endfor %}
    </ul>
  </li>
  {% endfor %}
</ul>
Chen Wang
Chen Wang
7,371 Points

Cool! Thanks, Chris!

Chris Jones
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Chris Jones
Java Web Development Techdegree Graduate 23,918 Points

Thanks for the help, Chris!

Could you tell me why this wouldn't work

<ul class="teachers">
  {% for teacher, course in teachers.items() %}
  <li>  
    <h2>
      {{ teacher }}
    </h2>
    <ul class="courses">
      {% for teacher, course in teachers.items() %}
        <li>
          {{ course }}
        </li>
      {% endfor %}
    </ul>
  </li>
  {% endfor %}
</ul>

I'm running the same for loop for task 1 and 2 but I'm just printing out the key (teacher name) in the first loop and the value (course name) in the second loop.

Thanks!

Chris Jones You cannot iterate using two values. Only one