Lesson 2
Creating ToDos with User Input
Creating ToDos with User Input

Welcome to the next lesson in our journey of building a ToDo App with Flask! In this lesson, we will focus on allowing users to create new Todo items through user input. This feature is essential because it empowers users to interact with the app and manage their tasks efficiently. By the end of this lesson, you will be able to accept input from users, create new Todo items, and display them within the application.

Defining the Add Method in TodoService

Let's first update our TodoService to create new Todo items from user input by adding a method that takes a title and description, generates a unique ID, and adds the new Todo to the list.

Python
1class TodoService: 2 def __init__(self): 3 self._todos = [ 4 Todo(1, "Sample Todo 1", "Description 1"), 5 Todo(2, "Sample Todo 2", "Description 2") 6 ] 7 8 def get_all(self): 9 return self._todos 10 11 def add(self, title, description): 12 # Calculate new ID for the new todo item 13 if self._todos: 14 # Find the maximum ID in the existing todos and add 1 to get the new ID 15 new_id = max(todo.todo_id for todo in self._todos) + 1 16 else: 17 # If the list is empty, start with ID 1 18 new_id = 1 19 # Create a new Todo object 20 new_todo = Todo(new_id, title, description) 21 # Add the new Todo to the list 22 self._todos.append(new_todo)

In this code, we define a method named add that receives a title and description, generates a new unique ID for the Todo item, creates the Todo object, and then adds it to the list of Todos:

  • Generate a New ID: We calculate the new ID by adding 1 to the maximum existing ID, or by starting at 1 if the list is empty.
  • Create a New Todo Object: We use the new ID, title, and description to create a new Todo object.
  • Add the Todo to the List: We append the new Todo object to the _todos list.

This approach ensures that each new Todo item has a unique ID and captures user input effectively. Now that we have addressed the service layer functionality for adding a Todo, let's move on to creating the controller endpoint to handle incoming user requests.

Creating the Add Route

Next, we need to update our controller to handle user input and add new Todo items. In todo_controller.py, let's add a new route to handle POST requests for adding new Todo items:

Python
1from flask import Blueprint, render_template, request, redirect, url_for 2from services.todo_service import TodoService 3 4todo_service = TodoService() 5 6todo_controller = Blueprint('todo', __name__) 7 8@todo_controller.route('/', methods=['GET']) 9def list_todos(): 10 todos = todo_service.get_all() 11 return render_template('todo_list.html', todos=todos) 12 13@todo_controller.route('/add', methods=['POST']) 14def add(): 15 # Retrieve title and description from the form data 16 title = request.form.get('title') 17 description = request.form.get('description') 18 # Check if both title and description are present 19 if title and description: 20 # Call the add method of TodoService with the title and description 21 todo_service.add(title, description) 22 # Redirect the user back to the Todo list view 23 return redirect(url_for('todo.list_todos'))

In the /add route, we handle the form submission from the user. A form is an HTML element that allows users to input data and send it to the server. When the user submits the form, it sends the data using a POST request, which is used in HTTP to send data to the server for creating or updating resources. We retrieve the data from the form using request.form.get() to get the values of the title and description fields.

After retrieving the form data, we check that both the title and description are provided. If they are, we call the add method of TodoService to create a new Todo item with the provided information. This adds the new item to our list of Todos.

Finally, we use redirect(url_for('todo.list_todos')) to send the user back to the main Todo list page. The redirect function tells the browser to open a different page, which, in this case, is the Todo list page. This refreshes the page so the user can see the new item they just added.

Understanding the Redirect Method

In our add route, after adding the new Todo item, we use a redirect to send the user back to the main Todo list page.

Here's the relevant line of code:

Python
1return redirect(url_for('todo.list_todos'))

Now, let's break this down to make it clear. The string 'todo.list_todos' is a way to point to a specific page in our app using the format blueprint_name.page_name.

  • todo is the name we defined for our Blueprint that groups our Todo routes. We created this with the line: todo_controller = Blueprint('todo', __name__).
  • list_todos is the name we gave to the function within the todo Blueprint that shows the list of Todos.

So, url_for('todo.list_todos') generates the URL for the page that displays all our Todos, based on the names we defined for the Blueprint and the function, not the actual URL route. This tells Flask exactly where to redirect the user after they add a new Todo item.

Updating the HTML Template

To enable users to input their Todo items, we need to update our HTML template to include a form. Here is the updated todo_list.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>Todo List</title> 7</head> 8<body> 9 <h1>Todo List</h1> 10 <ul> 11 {% for todo in todos %} 12 <li> 13 <strong>{{ todo.title }}</strong>: {{ todo.description }} 14 </li> 15 {% endfor %} 16 </ul> 17 <!-- Form to add a new todo item --> 18 <h2>Add New Todo</h2> 19 <form action="{{ url_for('todo.add') }}" method="POST"> 20 <label for="title">Title:</label> 21 <input type="text" id="title" name="title" required><br><br> 22 23 <label for="description">Description:</label> 24 <input type="text" id="description" name="description" required><br><br> 25 26 <button type="submit">Add Todo</button> 27 </form> 28</body> 29</html>

In the above HTML template, we included a form with fields to input the title and description of a new Todo item. When the form is submitted, it makes a POST request to the /add route to create the new Todo item. The current list of Todos is displayed above the form.

Understanding the Form's Action

By defining the action as {{ url_for('todo.add') }}, we connect the form submission to the add function in our Flask app. This function handles the form data and adds a new Todo item to our list.

HTML, XML
1<form action="{{ url_for('todo.add') }}" method="POST"> 2 <!-- Labels, inputs and button --> 3</form>

Let's break it down:

  • action="{{ url_for('todo.add') }}": This specifies the route to which the form data will be submitted.
    • url_for: A Flask function that generates a URL for a given endpoint.
    • 'todo.add': This refers to the add function in the todo Blueprint.
      • todo: The name of the Blueprint managing Todo routes (todo_controller = Blueprint('todo', __name__)).
      • add: The specific function in the todo Blueprint to handle adding a new Todo item.
  • method="POST": This tells the form to send data using the POST method, which is used to send data to the server to create or update resources.
Summary and Next Steps

In this lesson, we successfully:

  • Updated the TodoService to include an add method.
  • Added a new POST route in the controller to handle user input.
  • Integrated a form into our HTML template for user input.

You now have the capability to add new Todo items through user input, making your app interactive and functional. For the next steps, proceed to the practice exercises to reinforce what you've learned. Happy coding, and great job making it this far!

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