Welcome, aspiring developers and productivity enthusiasts! Today, we’re going to build something practical and fun: a simple To-Do List application using Flask. Flask is a popular, lightweight web framework for Python that makes building web applications surprisingly straightforward. If you’re new to web development or Flask, don’t worry – we’ll go step-by-step, explaining everything along the way.
What is Flask?
Before we dive into coding, let’s briefly understand what Flask is.
- Web Framework: Imagine you want to build a house. You could start from scratch, making every single brick, window, and door yourself. Or, you could use a pre-designed kit that gives you the foundation, walls, and a basic structure, allowing you to focus on the interior and unique features. Flask is like that pre-designed kit for building web applications. It provides the essential tools and structure so you don’t have to write everything from zero.
- Micro-framework: The “micro” in Flask means it aims to keep the core simple but extensible. It doesn’t force you into specific ways of doing things, giving you a lot of flexibility. This makes it perfect for beginners and for building smaller applications.
- Python: Flask is written in Python, which is known for its readability and simplicity. If you know a bit of Python, you’ll feel right at home!
Our To-Do list app will allow users to add tasks, view their tasks, mark them as complete, and delete them. For simplicity, our tasks will be stored directly in the application’s memory. This means if you restart the server, your tasks will disappear – a good point for “next steps” to introduce databases!
Setting Up Your Development Environment
First things first, let’s get your computer ready.
Prerequisites
You’ll need:
- Python 3: Most modern computers come with Python installed. You can check by opening your terminal or command prompt and typing
python3 --versionorpython --version. If it’s not installed, head to python.org to download and install it. - pip: This is Python’s package installer, usually included with Python 3. We’ll use it to install Flask.
Creating Your Project Folder and Virtual Environment
It’s good practice to create a dedicated folder for your project and use a “virtual environment.”
- Project Folder: This keeps all your app’s files organized.
- Virtual Environment (venv): Think of this as an isolated workspace for your project. When you install packages (like Flask), they’ll only be installed within this specific environment, preventing conflicts with other Python projects on your computer.
Let’s do it:
- Open your terminal or command prompt.
- Create a new folder for your project:
bash
mkdir flask-todo-app - Navigate into your new folder:
bash
cd flask-todo-app - Create a virtual environment named
venv:
bash
python3 -m venv venv
(On some systems, you might just usepython -m venv venv) -
Activate your virtual environment:
- On macOS/Linux:
bash
source venv/bin/activate - On Windows (Command Prompt):
bash
.\venv\Scripts\activate - On Windows (PowerShell):
bash
.\venv\Scripts\Activate.ps1
You’ll notice
(venv)appear at the beginning of your terminal prompt, indicating that the virtual environment is active.
6. Install Flask:
bash
pip install Flask - On macOS/Linux:
Great! Your environment is set up.
Your First Flask Application (app.py)
Every Flask application starts with a main Python file. Let’s call ours app.py.
- Inside your
flask-todo-appfolder, create a new file namedapp.py. -
Open
app.pyin your favorite code editor (like VS Code, Sublime Text, Atom, etc.) and add the following code:“`python
from flask import FlaskCreate a Flask web application instance.
name is a special Python variable that tells Flask where to look for resources.
app = Flask(name)
Define a route. A route is like a URL path (e.g., ‘/’) that users can visit.
When a user goes to the root URL (‘/’), this ‘index’ function will run.
@app.route(‘/’)
def index():
return “Hello, Flask To-Do App!”This ensures the Flask development server runs only when you execute app.py directly.
if name == ‘main‘:
# Run the Flask application.
# debug=True enables debugging mode, which automatically reloads the server on code changes
# and provides helpful error messages. Turn it off in production!
app.run(debug=True)
“`
Understanding the Code
from flask import Flask: This line imports theFlaskclass from theflasklibrary we installed.app = Flask(__name__): This creates an instance of our Flask application.@app.route('/'): This is a “decorator” that tells Flask which URL should trigger theindex()function. In this case,/refers to the root URL (e.g.,http://127.0.0.1:5000/).def index():: This is our “view function.” When someone visits the/URL, this function executes and returns “Hello, Flask To-Do App!”. Whatever this function returns is what the user’s browser will display.if __name__ == '__main__':: This is a standard Python idiom. It ensures thatapp.run()is called only whenapp.pyis executed directly (not when it’s imported as a module into another script).app.run(debug=True): This starts the development server.debug=Trueis super handy during development as it automatically restarts the server when you make changes to your code and gives you detailed error messages.
Running Your First App
- Save
app.py. - Go back to your terminal (making sure your
venvis still active). - Run the app:
bash
python app.py
You should see output similar to this:
“`- Serving Flask app ‘app’
- Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. - Running on http://127.0.0.1:5000
Press CTRL+C to quit - Restarting with stat
- Debugger is active!
- Debugger PIN: …
“`
- Open your web browser and go to
http://127.0.0.1:5000. You should see “Hello, Flask To-Do App!”.
Congratulations, your Flask app is running! Press CTRL+C in your terminal to stop the server when you’re done.
Building the To-Do List Logic
Now, let’s turn our “Hello, World!” app into a functional To-Do list. We’ll need a way to store tasks and display them.
Storing Tasks (Temporary)
For this simple app, we’ll store our tasks in a Python list right within app.py. Each task will be a dictionary with an id, content (the task description), and a done status.
Modify your app.py to include a tasks list:
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
tasks = []
task_id_counter = 1 # To assign unique IDs to tasks
@app.route('/')
def index():
"""Displays the main To-Do list page."""
# We will soon render an HTML template here instead of just text.
return "This is where our To-Do list will be displayed!"
@app.route('/add', methods=['POST'])
def add_task():
"""Handles adding new tasks."""
global task_id_counter # Declare we're modifying the global counter
task_content = request.form['content'] # Get task content from the submitted form
if task_content:
tasks.append({'id': task_id_counter, 'content': task_content, 'done': False})
task_id_counter += 1
return redirect(url_for('index')) # Redirect back to the homepage after adding
@app.route('/complete/<int:task_id>')
def complete_task(task_id):
"""Handles marking tasks as complete/incomplete."""
for task in tasks:
if task['id'] == task_id:
task['done'] = not task['done'] # Toggle the 'done' status
break
return redirect(url_for('index'))
@app.route('/delete/<int:task_id>')
def delete_task(task_id):
"""Handles deleting tasks."""
global tasks # Declare we're modifying the global tasks list
# Filter out the task with the given ID
tasks = [task for task in tasks if task['id'] != task_id]
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
New Imports and Concepts:
render_template: A Flask function that lets us use HTML files as templates.request: An object that holds incoming request data, like form submissions.redirect: A function to redirect the user’s browser to a different URL.url_for: A helper function to build URLs dynamically, based on the function name associated with a route. This is safer and more robust than hardcoding URLs.methods=['POST']: This tells Flask that the/addroute should only acceptPOSTrequests, which are typically used when submitting form data.request.form['content']: When a form is submitted, its data is available throughrequest.form.contentrefers to thenameattribute of the input field in our HTML form.global tasks: When you want to modify a global variable (liketasksortask_id_counter) inside a function, you need to explicitly declare it asglobal.
Using HTML Templates (templates folder)
Returning plain text from our index() function isn’t very exciting. We need proper HTML to display our To-Do list nicely. Flask uses a templating engine called Jinja2 to render HTML files.
- Create a
templatesfolder: In yourflask-todo-appdirectory, create a new folder namedtemplates. Flask automatically looks for HTML templates in this folder. -
Create
index.html: Inside thetemplatesfolder, create a file namedindex.htmland add the following code:“`html
<!DOCTYPE html>
My Simple Flask To-Do App
My Simple Flask To-Do List
<form class="task-form" action="{{ url_for('add_task') }}" method="POST"> <input type="text" name="content" placeholder="Add a new task..." required> <button type="submit">Add Task</button> </form> <h2>Current Tasks</h2> {% if tasks %} <ul> {% for task in tasks %} <li class="{{ 'done' if task.done }}"> <span>{{ task.content }}</span> <div class="task-actions"> <a href="{{ url_for('complete_task', task_id=task.id) }}" class="{% if task.done %}undo-btn{% else %}complete-btn{% endif %}"> {% if task.done %}Undo{% else %}Complete{% endif %} </a> <a href="{{ url_for('delete_task', task_id=task.id) }}" class="delete-btn">Delete</a> </div> </li> {% endfor %} </ul> {% else %} <p class="no-tasks">No tasks yet! Add one above to get started.</p> {% endif %}
“`
Jinja2 Templating Basics:
{{ ... }}: This is used to display variables or results of expressions. For example,{{ task.content }}will print the content of a task.{% ... %}: This is used for control flow statements likeifconditions orforloops.{% if tasks %}…{% else %}…{% endif %}: Conditionally renders content.{% for task in tasks %}…{% endfor %}: Loops through a list of items.
{{ url_for('add_task') }}: Dynamically generates the URL for theadd_taskfunction defined inapp.py. This is much better than hardcoding/add.
Connecting app.py with index.html
Finally, let’s update our index() function in app.py to render our index.html template.
Modify the index() function in your app.py file:
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
tasks = []
task_id_counter = 1
@app.route('/')
def index():
"""Displays the main To-Do list page."""
# Render the index.html template and pass the 'tasks' list to it.
return render_template('index.html', tasks=tasks) # <--- THIS IS THE CHANGE
@app.route('/add', methods=['POST'])
def add_task():
global task_id_counter
task_content = request.form['content']
if task_content:
tasks.append({'id': task_id_counter, 'content': task_content, 'done': False})
task_id_counter += 1
return redirect(url_for('index'))
@app.route('/complete/<int:task_id>')
def complete_task(task_id):
for task in tasks:
if task['id'] == task_id:
task['done'] = not task['done']
break
return redirect(url_for('index'))
@app.route('/delete/<int:task_id>')
def delete_task(task_id):
global tasks
tasks = [task for task in tasks if task['id'] != task_id]
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
Running Your Complete To-Do App
- Make sure you’ve saved both
app.pyandtemplates/index.html. - If your Flask server is still running from before, stop it (
CTRL+C). - Ensure your virtual environment is active.
- Run your app again:
bash
python app.py - Open your browser to
http://127.0.0.1:5000.
You should now see a simple To-Do list interface! Try adding tasks, marking them complete, and deleting them. Remember, because we’re not using a database yet, your tasks will disappear if you stop and restart the server.
Next Steps and Further Improvements
You’ve built a fully functional (albeit simple) To-Do list app with Flask! Here are some ideas for how you can expand and improve it:
- Persistence with Databases: Instead of storing tasks in a Python list, use a database like SQLite (built into Python!) with a library like SQLAlchemy or Flask-SQLAlchemy. This will make your tasks permanent.
- Better Styling: While we added some basic CSS, you could integrate a CSS framework like Bootstrap or Tailwind CSS for a more polished and responsive user interface.
- User Authentication: Add user login and registration so multiple users can have their own To-Do lists.
- Error Handling: Implement more robust error handling for invalid inputs or unexpected issues.
- Task Editing: Add a feature to edit existing tasks.
Conclusion
We’ve covered a lot in this guide! You’ve learned how to set up a Flask project, understand basic Flask concepts like routes and view functions, handle form submissions, and render dynamic HTML templates. Building a To-Do list is a fantastic way to grasp the fundamentals of web application development. Keep experimenting, and happy coding!
Leave a Reply
You must be logged in to post a comment.