Change Display¶
We currently let the route decide what to display in the listing of todos. We should let the todo be in charge of its formatting, for consistency across our app.
We will use this change to illustrate the following debugger concepts:
- Watches
- Conditional breakpoints
Steps¶
In
models.py
, let’s change the assigned display format to also show theid
:self.display_fmt = '{title} (ID: {todo_id})'
Let’s change the
display
property we use to calculate and return the display value:@property def display(self): return self.display_fmt.format(todo_id=self.id, title=self.title)
Just to be clean, let’s change our
__repr__
to use this:def __repr__(self): return self.display
In
app.py
, changelist_todos
to uset.display
instead oft.title
:items = [div.format(id=t.id, title=t.display) for t in todos]
Using the debugger, we’d like to see the calculated value for the last todo. Put the breakpoint in
models.py
on this line:return self.display_fmt.format(todo_id=self.id, title=self.title)
Click the Debugger’s
Rerun
button then reload the todo listing in in the browser.Click
Resume
several times until you get to the fifth todo, then useEvaluate Expression
to see the value ofself.display
.Let’s make that more efficient using a watch, which is a way to calculate an expression and show in the debugger’s
Variables
as you move through code.In
Variables
panel, click the+
button forNew Watch
.In the input prompt, type this expression and hit enter:
``self.display_fmt.format(todo_id=self.id, title=self.title)``
Click the
Rerun
button then reload the todo listing in in the browser.This time, as you step through to the last todo, the watch shows you the calculated value that will be returned.
It is still inefficient to step until you reach the todo. Let’s make a conditional breakpoint, which only stops when an expression is true.
Right-click on your breakpoint inside
def display
. In theCondition
box, enterself.id == 4
.Click the
Rerun
button then reload the todo listing in in the browser.Note that the debugger this time stops only at the 4th todo.
Your
models.py
should match the following:from random import choice todos = [] class Todo: def __init__(self, title): self.title = title self.display_fmt = '{title} (ID: {todo_id})' self.id = max([todo.id for todo in todos], default=0) + 1 def __repr__(self): return self.display @property def display(self): return self.display_fmt.format(todo_id=self.id, title=self.title) @staticmethod def list(): return sorted(todos, key=lambda todo: todo.title) @staticmethod def add(title): todo = Todo(title) todos.append(todo) return todo def delete(self): todos.remove(self) @staticmethod def get_id(todo_id): return [todo for todo in todos if todo.id == todo_id][0] def populate_todos(): random_verbs = ['Make', 'Buy', 'Organize', 'Finish'] random_nouns = ['Red', 'Apple', 'Blue', 'Tomato', 'Green', 'Pear', 'Black', 'Bean', 'Yellow', 'Banana', 'Brown', 'Raisin'] for i in range(5): v = choice(random_verbs) w1 = choice(random_nouns) w2 = choice(random_nouns) title = '{v} {w1} {w2}'.format(v=v, w1=w1, w2=w2) Todo.add(title) if __name__ == '__main__': populate_todos() first_todo = Todo.list()[0] first_id = first_todo.id print(Todo.get_id(first_id))
Your
app.py
should match the following:from flask import Flask, request from flask import redirect from models import populate_todos, Todo app = Flask(__name__) @app.route('/', methods=['POST', 'GET']) def home_page(): return 'Hello World! <a href="/todo/">Todos</a>' @app.route('/todo/') def list_todos(): todos = Todo.list() div = '''<div><a href="/todo/{id}/delete">{title}</a> <form method="POST" action="/todo/{id}/delete" style="display: inline"> <input type="submit" value="x"/> </form> </div>''' form = '''<form method="POST" action="add"> <input name="todo_id" placeholder="Add todo..."/> </form> ''' items = [div.format(id=t.id, title=t.display) for t in todos] items.append(form) return '\n'.join(items) @app.route('/todo/<int:todo_id>') def show_todo(todo_id): todo = Todo.get_id(todo_id) fmt = '<h1>Todo {todo_id}</h1><p>{title}</p>' return fmt.format(todo_id=todo.id, title=todo.title) @app.route('/todo/add', methods=['POST', 'GET']) def add_todo(): todo_id = request.form['todo_id'] if request.method == 'POST': print('POSTed') else: print('GETed') if todo_id: Todo.add(todo_id) return redirect('/todo/') @app.route('/todo/<int:todo_id>/delete', methods=['POST']) def delete_todo(todo_id): todo = Todo.get_id(todo_id) todo.delete() return redirect('/todo/') if __name__ == '__main__': populate_todos() app.run(debug=True)
- Previous topic: Delete Todo
- Next topic: Templating