Building a Simple Project Management Tool with Flask

Welcome, aspiring developers and productivity enthusiasts! Ever felt overwhelmed by your to-do list? A simple project management tool can be a lifesaver. Today, we’re going to embark on an exciting journey to build our very own basic project management application using Flask, a lightweight yet powerful Python web framework. Don’t worry if you’re new to web development; we’ll break down every step into easy-to-understand pieces.

What is Flask and Why Choose It?

Flask is what we call a “micro” web framework for Python. Think of a web framework as a helpful toolkit that gives you the basic structure and tools to build websites and web applications without having to start completely from scratch. Flask is “micro” because it’s designed to be simple and flexible, providing just the essentials. This makes it a fantastic choice for beginners to learn web development, and it’s also powerful enough for complex projects.

We’re choosing Flask because:
* It’s easy to learn: Its simplicity allows you to grasp core web development concepts quickly.
* It’s flexible: You can add any other tools or libraries you like, making it highly adaptable.
* It’s Pythonic: If you know Python, Flask will feel very natural to use.

What We’ll Build

Our goal is to create a basic web application that allows us to manage tasks for a project. Specifically, we’ll implement the fundamental CRUD operations:
* Create: Add new tasks.
* Read: View all existing tasks.
* Update: Edit the details of an existing task.
* Delete: Remove tasks that are completed or no longer needed.

For simplicity, we’ll start by storing our tasks in your computer’s memory. This means tasks will disappear if you restart the application. Later, you can upgrade to a database for permanent storage!

Prerequisites

Before we begin, make sure you have the following ready:
* Python: Version 3.6 or higher installed on your computer. You can download it from the official Python website.
* A Text Editor: Like VS Code, Sublime Text, or Atom.
* Basic Understanding of Python: Knowing variables, lists, and functions will be helpful.
* Command Line Basics: How to navigate directories and run commands in your terminal or command prompt.

Setting Up Your Development Environment

First things first, let’s set up a clean workspace for our project. It’s always a good practice to use a virtual environment. A virtual environment (venv) is like an isolated sandbox for your Python project. It allows you to install specific Python packages for one project without them interfering with other projects or your main Python installation.

  1. Create a Project Folder:
    Open your terminal or command prompt and create a new directory for your project:
    bash
    mkdir simple_project_manager
    cd simple_project_manager

  2. Create a Virtual Environment:
    Inside your project folder, create a virtual environment named venv:
    bash
    python -m venv venv

  3. Activate the Virtual Environment:

    • On macOS/Linux:
      bash
      source venv/bin/activate
    • On Windows:
      bash
      venv\Scripts\activate

      You’ll notice (venv) appear at the beginning of your command prompt, indicating that your virtual environment is active.
  4. Install Flask:
    Now that your virtual environment is active, let’s install Flask:
    bash
    pip install Flask

Building the Core Application Structure

Our simple project manager will have two main parts:
* app.py: This Python file will contain all our Flask application logic.
* templates/: This folder will hold our HTML files that Flask uses to display content in the web browser.

Let’s create these:

touch app.py
mkdir templates

Creating the Flask Application (app.py)

Now, open app.py in your text editor and let’s start writing our Flask application.

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():
    # render_template looks for HTML files in the 'templates' folder.
    # We pass our 'tasks' list to the template so it can display them.
    return render_template('index.html', tasks=tasks)

@app.route('/add', methods=['POST'])
def add_task():
    global task_id_counter
    # Get the task description from the submitted form data.
    task_description = request.form['description']
    if task_description: # Make sure the description isn't empty
        tasks.append({'id': task_id_counter, 'description': task_description})
        task_id_counter += 1
    # After adding, redirect the user back to the homepage.
    return redirect(url_for('index'))

@app.route('/edit/<int:task_id>', methods=['GET', 'POST'])
def edit_task(task_id):
    task = next((t for t in tasks if t['id'] == task_id), None)
    if not task:
        return redirect(url_for('index')) # Task not found, go back home

    if request.method == 'POST':
        new_description = request.form['description']
        if new_description:
            task['description'] = new_description
        return redirect(url_for('index'))

    # For GET request, show the edit form with current task description
    return render_template('edit.html', task=task)

@app.route('/delete/<int:task_id>', methods=['POST'])
def delete_task(task_id):
    global tasks
    # Filter out the task with the given ID
    tasks = [task for task in tasks if task['id'] != task_id]
    # Redirect back to the homepage
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run(debug=True) # debug=True allows the server to auto-reload on code changes and provides useful error messages.

Let’s break down some concepts in the code:
* Flask(__name__): Initializes our Flask application. __name__ refers to the current Python module.
* @app.route('/'): This is a decorator that tells Flask which URL (/ in this case) should trigger the index() function.
* render_template('index.html', tasks=tasks): This function from Flask looks for index.html inside your templates folder and uses the Jinja2 templating engine to fill in dynamic data (like our tasks list).
* request.form['description']: When a user submits an HTML form with method="POST", the data comes in through request.form. We access the value of the input field named description.
* redirect(url_for('index')): After performing an action (like adding a task), it’s good practice to redirect the user to another page (like the homepage) to prevent accidental re-submission if they refresh the page. url_for('index') generates the URL for the index function.
* methods=['POST']: This specifies that the route should only respond to HTTP POST requests, which are typically used when submitting data from a form. Similarly, methods=['GET', 'POST'] means it can handle both.

Creating the HTML Templates

Now, let’s create the HTML files that our Flask application will use to display content to the user.

templates/index.html

Create a file named index.html inside your templates folder:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Project Manager</title>
    <style>
        /* Basic CSS for a slightly better look */
        body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
        h1 { color: #0056b3; }
        form { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px; }
        input[type="text"], input[type="submit"] { padding: 10px; border-radius: 4px; border: 1px solid #ddd; }
        input[type="submit"] { background-color: #007bff; color: white; cursor: pointer; border: none; }
        input[type="submit"]:hover { background-color: #0056b3; }
        ul { list-style: none; padding: 0; }
        li { background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; }
        .task-actions form { display: inline-block; margin-left: 10px; padding: 0; background: none; box-shadow: none; }
        .task-actions button { background: #dc3545; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer; font-size: 0.9em; }
        .task-actions button.edit-btn { background: #ffc107; color: #333; }
        .task-actions button:hover { opacity: 0.9; }
    </style>
</head>
<body>
    <h1>My Project Tasks</h1>

    <form action="{{ url_for('add_task') }}" method="post">
        <input type="text" name="description" placeholder="Add a new task..." required>
        <input type="submit" value="Add Task">
    </form>

    <h2>Current Tasks</h2>
    {% if tasks %}
    <ul>
        {% for task in tasks %}
        <li>
            <span>{{ task.description }}</span>
            <div class="task-actions">
                <form action="{{ url_for('edit_task', task_id=task.id) }}" method="get">
                    <button type="submit" class="edit-btn">Edit</button>
                </form>
                <form action="{{ url_for('delete_task', task_id=task.id) }}" method="post">
                    <button type="submit">Delete</button>
                </form>
            </div>
        </li>
        {% endfor %}
    </ul>
    {% else %}
    <p>No tasks yet! Start by adding one above.</p>
    {% endif %}
</body>
</html>

In index.html:
* {{ variable_name }}: This is how Jinja2 displays dynamic content passed from Flask.
* {% if condition %} / {% for item in list %}: These are Jinja2’s control structures, similar to Python’s if and for loops, used to conditionally display content or iterate over lists.
* action="{{ url_for('add_task') }}": This dynamically generates the URL for the add_task function in our app.py.

templates/edit.html

Create a file named edit.html inside your templates folder:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Edit Task</title>
    <style>
        body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
        h1 { color: #0056b3; }
        form { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px; }
        input[type="text"], input[type="submit"] { padding: 10px; border-radius: 4px; border: 1px solid #ddd; }
        input[type="submit"] { background-color: #28a745; color: white; cursor: pointer; border: none; }
        input[type="submit"]:hover { background-color: #218838; }
        .back-link { display: block; margin-top: 20px; color: #007bff; text-decoration: none; }
        .back-link:hover { text-decoration: underline; }
    </style>
</head>
<body>
    <h1>Edit Task: {{ task.id }}</h1>

    <form action="{{ url_for('edit_task', task_id=task.id) }}" method="post">
        <input type="text" name="description" value="{{ task.description }}" required>
        <input type="submit" value="Update Task">
    </form>
    <a href="{{ url_for('index') }}" class="back-link">Back to Task List</a>
</body>
</html>

This edit.html provides a form to update a task’s description, pre-filling the input field with the current description.

Running Your Application

You’re almost there! Now it’s time to see your creation in action.

  1. Ensure your virtual environment is active. If not, activate it again (source venv/bin/activate or venv\Scripts\activate).
  2. Navigate to your project directory (where app.py is located) in your terminal.
  3. Run the Flask application:
    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: XXX-XXX-XXX
      “`
  4. Open your web browser and go to http://127.0.0.1:5000.

Congratulations! You should now see your very own simple project management tool. You can add tasks, edit them, and delete them. Remember, since we’re using in-memory storage, your tasks will vanish if you stop and restart the server.

Next Steps and Further Improvements

This is just the beginning! Here are some ideas to expand your project:

  • Database Integration: To store tasks permanently, integrate a database like SQLite (which is built into Python) or PostgreSQL. This would involve using an ORM (Object-Relational Mapper) like SQLAlchemy.
  • Better UI/UX: Use a CSS framework like Bootstrap or Tailwind CSS to make your application look more professional and responsive.
  • Task Status and Due Dates: Add fields for task status (e.g., “pending”, “in progress”, “completed”) and due dates.
  • User Authentication: Implement user login and registration so different users can manage their own tasks.
  • Task Prioritization: Add a priority level to tasks (e.g., high, medium, low).
  • Deployment: Learn how to deploy your Flask application to a web server so others can access it online.

Conclusion

You’ve just built a functional web application using Flask! This is a fantastic achievement and a solid foundation for diving deeper into web development. You’ve learned about Flask’s core concepts, handling web requests, rendering templates, and performing basic data manipulation. Keep experimenting, keep building, and enjoy the exciting world of web development!


Comments

Leave a Reply