Lesson 3
Updating Existing ToDos
Updating Existing ToDos

Welcome back! You've already made great progress by learning how to list and create todo items in your Flask application. Now, we will enhance your ToDo app by adding the ability to edit existing todo items. This feature is essential in any task management app, as it allows users to update and refine their tasks as needed.

By the end of this lesson, you will be able to:

  • Retrieve an existing todo item for editing.
  • Update the todo item with new details and save the changes.

Let's dive in!

Service Layer: Updating Todos

First, let's focus on the TodoService class and the update method. This method will allow us to modify the existing todo items.

Python
1class TodoService: 2 3 # Constructor and other methods... 4 5 # Method to retrieve an item by its ID 6 def get_by_id(self, todo_id): 7 # Iterate through the list of todos to find the matching ID 8 for todo in self._todos: 9 # Return the matching todo item 10 if todo.todo_id == todo_id: 11 return todo 12 # Return None if no matching item is found 13 return None 14 15 # Method to update an item using its ID 16 def update(self, todo_id, title, description): 17 # Retrieve the todo item by its ID 18 todo = self.get_by_id(todo_id) 19 if todo: 20 # Update the title and description of the todo item 21 todo.title = title 22 todo.description = description 23 # Return True if the update was successful 24 return True 25 # Return False if the todo item was not found 26 return False

Here, we define two methods within the TodoService class. The get_by_id method searches for and returns a todo item by its unique identifier. If found, the item is returned; otherwise, None is returned.

The update method leverages this retrieval functionality and updates an existing todo item's title and description. If the item is found and updated, the method returns True; otherwise, it returns False.

Controller Layer: Handling Edit and Update Requests

Now, let's move on to the controller layer. We will handle routes for displaying the edit form and for submitting updates.

Here are the relevant routes in todo_controller.py:

Python
1from flask import Blueprint, render_template, request, redirect, url_for 2from services.todo_service import TodoService 3 4todo_service = TodoService() 5todo_controller = Blueprint('todo', __name__) 6 7# Routes for listing and adding items... 8 9# Route for rendering a page for a specific todo item 10@todo_controller.route('/edit/<int:todo_id>', methods=['GET']) 11def edit_todo(todo_id): 12 # Retrieve the todo item by its ID 13 todo_item = todo_service.get_by_id(todo_id) 14 if not todo_item: 15 # Redirect to list view if the todo item is not found 16 return redirect(url_for('todo.list_todos')) 17 # Render the edit template with the retrieved todo item 18 return render_template('todo_edit.html', todo=todo_item) 19 20# Route for updating the data of a specific todo item 21@todo_controller.route('/update/<int:todo_id>', methods=['POST']) 22def update(todo_id): 23 title = request.form.get('title') 24 description = request.form.get('description') 25 if title and description: 26 # Update the todo item with new title and description 27 todo_service.update(todo_id, title, description) 28 # Redirect to the list view after updating 29 return redirect(url_for('todo.list_todos'))

In this segment, we set up two new routes:

  1. Edit Route: The edit_todo route displays a form for editing a specific todo item. It uses the get_by_id method to retrieve the item and renders the todo_edit.html template for editing. If the item isn't found, it redirects back to the list view.
  2. Update Route: The update route handles form submission, extracts the new title and description from the request, updates the todo item using the update method, and then redirects back to the main todo list. Although there are other HTTP methods more suited for update operations, such as PUT, we will use POST because HTML forms only natively support GET and POST methods.

Note that we use route parameters (e.g., <int:todo_id>) to capture dynamic values directly from the URL. For example, <int:todo_id> means todo_id is an integer parameter. In a URL, it might look like /edit/1 where 1 is the todo_id.

This allows us to pass the specific todo_id to the route functions for precise item handling.

List Template: Adding Links to Edit Items

Before we create the editing form, we need to modify the part of our main page template that lists the items to include a way to select a specific todo item and redirect to its editing page.

Update the todo_list.html template as follows:

HTML, XML
1<ul> 2 {% for todo in todos %} 3 <li> 4 <strong>{{ todo.title }}</strong>: {{ todo.description }} 5 <!-- Link to the edit page for the specific todo item --> 6 <a href="{{ url_for('todo.edit_todo', todo_id=todo.todo_id) }}">Edit</a> 7 </li> 8 {% endfor %} 9</ul>

We upgrade our todo_list.html template by adding an "Edit" link next to each todo item. For every todo item listed, the link redirects to the edit_todo route, where users can edit the specific todo item. This link is generated using Flask's url_for function, which dynamically creates the appropriate URL based on the todo_id.

Edit Template: Editing Form

Next, let's create the HTML template with the form for editing a todo item.

Here is the todo_edit.html template:

HTML, XML
1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Edit Todo</title> 7</head> 8<body> 9 <h1>Edit Todo</h1> 10 11 <!-- Form for editing the selected todo --> 12 <form action="{{ url_for('todo.update', todo_id=todo.todo_id) }}" method="POST"> 13 <!-- Field for editing the title with current value pre-filled --> 14 <label for="title">Title:</label> 15 <input type="text" id="title" name="title" value="{{ todo.title }}" required><br><br> 16 <!-- Field for editing the description with current value pre-filled --> 17 <label for="description">Description:</label> 18 <input type="text" id="description" name="description" value="{{ todo.description }}" required><br><br> 19 <!-- Button to submit the form and update the todo item --> 20 <button type="submit">Update</button> 21 </form> 22 <!-- Link to go back to the main todo list --> 23 <a href="{{ url_for('todo.list_todos') }}">Back to List</a> 24</body> 25</html>

We then create the todo_edit.html template, which displays a form for editing a specific todo item. The form is pre-filled with the current title and description of the todo item, allowing users to make changes. Upon submitting the form, the data is sent to the update route using a POST request. Additionally, we provide a "Back to List" link to return to the main todo list without making any changes.

Connecting it All Together

Let's walk through an end-to-end example to ensure everything works seamlessly:

  1. Initiate Edit:

    • From the list view, click the "Edit" link next to a todo item. This action will navigate to the /edit/<int:todo_id> route using the item's ID.
  2. Edit Form:

    • The form in todo_edit.html is displayed with the current details of the todo item pre-filled.
  3. Submit Changes:

    • Modify the title and description as needed, and click the "Update" button. This submits the form to the /update/<int:todo_id> route using the item's ID.
  4. Update Processing:

    • The update method in TodoService is called to apply the changes.
    • Finally, the user is redirected back to the main todo list view, where the updated item is displayed.
Summary and Preparation for Practice

In this lesson, you learned how to enhance your ToDo app by enabling users to edit existing todo items. We covered:

  • Updating the service layer to support modifications.
  • Handling edit and update requests in the controller.
  • Creating an edit form in the user interface.

Next, proceed to the practice exercises to apply these concepts and solidify your understanding. Great job, and keep up the excellent work in building your ToDo app!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.