List Todos Template

We’ll convert another view to use a view template with a master template. In the process, we’ll get our first real use of the debugger by setting a breakpoint in the template.

Steps

  1. Let’s make a template in templates/list_todos.html:

    templates/list_todos.html in List Todos Templates
    {% extends "layout.html" %}
    {% block content %}
        <ul>
            {% for todo in todos %}
                <li>
                    <a href="/todo/{{ todo.id }}">{{ todo.title }}</a>
                </li>
            {% endfor %}
        </ul>
    {% endblock %}
    
  2. In app.py, change the list_todos, making it much simpler: it just hands data to the template:

    def list_todos():
        todos = Todo.list()
        return render_template('list_todos.html', page_title='List Todos', todos=todos)
    

    Note: The page_title mistake is intentional.

  3. Next, let’s do the same for show_todo. First, create templates/show_todo.html:

    templates/show_todo.html in List Todos Templates
    {% extends "layout.html" %}
    {% block content %}
        <p>{{ todo.title }}</p>
    {% endblock %}
    
  4. In app.py, change the show_todo, also making it much simpler: it just hands data to the template:

    def show_todo(todo_id):
        todo = Todo.get_id(todo_id)
        return render_template('show_todo.html', title='Todo ' + str(todo_id), todo=todo)
    

    Note: PyCharm Professional autocompletes the template filename from the ``templates`` directory, which is very helpful.

  5. In your browser, visit the List Todos page. We aren’t getting a title displayed. Let’s debug it.

  6. Open templates/layout.html and click in the left margin on the second line, where <head><title> occurs. Your click should create a red circle for a “breakpoint”.

  7. Reload your browser. PyCharm switches back in view, with the execution “stopped” on that line.

  8. Look in the “Variables” window at the bottom. You see all the Python values defined at that point in the template. You realize title isn’t there, but page_title is, thus your error.

  9. In the Debug Tool window, click the green arrow play button to “Resume Program”.

  10. In app.py, change page_title to title.

  11. Reload the browser and execution again stops in that place. Confirm that a title variable exists and click the green arrow again to Resume Program.

  12. Now, the browser provides the List Todos heading.

  13. Click the red circle to clear the breakpoint.

  14. Let’s set a breakpoint in the loop. In list_todos.html, click in the left margin on the <a> in the <li>.

  15. Reload the browser. When execution stops, in the Variables pane, note that todo is defined. Expand it to see what information it contains.

  16. Your app.py should match the following:

    app.py in List Todos
    from flask import Flask
    from flask import render_template
    
    from models import populate_todos, Todo
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def home_page():
        return render_template('home_page.html', title='Home Page')
    
    
    @app.route('/todo/')
    def list_todos():
        todos = Todo.list()
        return render_template('list_todos.html', title='List Todos', todos=todos)
    
    
    @app.route('/todo/<int:todo_id>')
    def show_todo(todo_id):
        todo = Todo.get_id(todo_id)
        return render_template('show_todo.html', title='Todo ' + str(todo_id), todo=todo)
    
    
    if __name__ == '__main__':
        populate_todos()
        app.run(debug=True)
    
  17. Your templates/list_todos.html should match the following:

    templates/list_todos.html in List Todos Templates
    {% extends "layout.html" %}
    {% block content %}
        <ul>
            {% for todo in todos %}
                <li>
                    <a href="/todo/{{ todo.id }}">{{ todo.title }}</a>
                </li>
            {% endfor %}
        </ul>
    {% endblock %}
    
  18. Your templates/show_todo.html should match the following:

    templates/list_todos.html in List Todos Templates
    {% extends "layout.html" %}
    {% block content %}
        <p>{{ todo.title }}</p>
    {% endblock %}