Home Backend Development Python Tutorial Task Manager App with Flask and MySQL

Task Manager App with Flask and MySQL

Nov 17, 2024 am 08:19 AM

Project Overview

This project is a Task Manager App built with Flask and MySQL. It provides a simple RESTful API to manage tasks, demonstrating basic CRUD (Create, Read, Delete) operations.

This application is perfect for understanding how Flask applications can be containerized using Docker and connected with a MySQL database.

Features

  • Add new tasks
  • View all tasks
  • Delete a task by ID

Flask Code: app.py

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

from flask import Flask, request, jsonify

import mysql.connector

from mysql.connector import Error

 

app = Flask(__name__)

 

# Database connection function

def get_db_connection():

    try:

        connection = mysql.connector.connect(

            host="db",

            user="root",

            password="example",

            database="task_db"

        )

        return connection

    except Error as e:

        return str(e)

 

# Route for the home page

@app.route('/')

def home():

    return "Welcome to the Task Management API! Use /tasks to interact with tasks."

 

# Route to create a new task

@app.route('/tasks', methods=['POST'])

def add_task():

    task_description = request.json.get('description')

    if not task_description:

        return jsonify({"error": "Task description is required"}), 400

 

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("INSERT INTO tasks (description) VALUES (%s)", (task_description,))

    connection.commit()

    task_id = cursor.lastrowid

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task added successfully", "task_id": task_id}), 201

 

# Route to get all tasks

@app.route('/tasks', methods=['GET'])

def get_tasks():

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("SELECT id, description FROM tasks")

    tasks = cursor.fetchall()

    cursor.close()

    connection.close()

 

    task_list = [{"id": task[0], "description": task[1]} for task in tasks]

    return jsonify(task_list), 200

 

# Route to delete a task by ID

@app.route('/tasks/<int:task_id>', methods=['DELETE'])

def delete_task(task_id):

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("DELETE FROM tasks WHERE id = %s", (task_id,))

    connection.commit()

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task deleted successfully"}), 200

 

if __name__ == "__main__":

    app.run(host='0.0.0.0')

Copy after login
Copy after login
Copy after login
Copy after login

MySQL Database Setup Script

Create a MySQL script named init-db.sql to set up the database and the tasks table:

To create the init-db.sql script, follow these steps:

Create a new file in your project directory:

Navigate to the project folder and create a new file named init-db.sql
Add SQL commands to set up the database and tasks table:

Open init-db.sql in a text editor and add the following SQL commands:

1

2

3

4

5

6

7

CREATE DATABASE IF NOT EXISTS task_db;

USE task_db;

 

CREATE TABLE IF NOT EXISTS tasks (

    id INT AUTO_INCREMENT PRIMARY KEY,

    description VARCHAR(255) NOT NULL

);

Copy after login
Copy after login
Copy after login

Save the file:

I saved the file as init-db.sql in the project folder where my docker-compose.yml is located.

In the docker-compose.yml:

In my docker-compose.yml file, I have the volumes configuration that points to this script.

Below is the docker-compose.yml file

Docker Configuration

docker-compose.yml:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

version: '3'

services:

  db:

    image: mysql:5.7

    environment:

      MYSQL_ROOT_PASSWORD: example

      MYSQL_DATABASE: task_db

    ports:

      - "3306:3306"

    volumes:

      - db_data:/var/lib/mysql

      - ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql

 

  web:

    build: .

    ports:

      - "5000:5000"

    depends_on:

      - db

    environment:

      FLASK_ENV: development

    volumes:

      - .:/app

 

volumes:

  db_data:

Copy after login
Copy after login
Copy after login

This configuration ensures that when the MySQL container starts, it will execute the init-db.sql script to set up the task_db database and create the tasks table.

Note: The docker-entrypoint-initdb.d/ directory is used by MySQL containers to execute .sql scripts during the initial startup of the container.

Explanation:

1. version: '3': Specifies the version of Docker Compose being used.

2. services:

  • db:

    • image: mysql:5.7: Uses the MySQL 5.7 image.
    • environment: Sets environment variables for the MySQL container:
      • MYSQL_ROOT_PASSWORD: The root password for MySQL.
      • MYSQL_DATABASE: The database to be created at startup.
    • ports: Maps the MySQL container's port 3306 to your host's port 3306.
    • volumes:
      • db_data:/var/lib/mysql: Persists the database data in a Docker volume called db_data.
      • ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql: Mounts the init-db.sql script into the MYSQL container's initialization directory so it runs when the container starts.
  • web:

    • build: .: Builds the Docker image for your Flask app using the Dockerfile in the current directory.
    • ports: Maps the Flask app's port 5000 to your host's port 5000.
    • depends_on: Ensures that the db service starts before the web service.
    • environment: Sets the environment variable for Flask.
    • volumes: Mounts the current project directory into the /app directory inside the container. ### volumes section: db_data: Defines a named volume db_data to persist the MySQL data between container restarts.

Dockerfile:

Define the build instructions for the Flask app:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

from flask import Flask, request, jsonify

import mysql.connector

from mysql.connector import Error

 

app = Flask(__name__)

 

# Database connection function

def get_db_connection():

    try:

        connection = mysql.connector.connect(

            host="db",

            user="root",

            password="example",

            database="task_db"

        )

        return connection

    except Error as e:

        return str(e)

 

# Route for the home page

@app.route('/')

def home():

    return "Welcome to the Task Management API! Use /tasks to interact with tasks."

 

# Route to create a new task

@app.route('/tasks', methods=['POST'])

def add_task():

    task_description = request.json.get('description')

    if not task_description:

        return jsonify({"error": "Task description is required"}), 400

 

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("INSERT INTO tasks (description) VALUES (%s)", (task_description,))

    connection.commit()

    task_id = cursor.lastrowid

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task added successfully", "task_id": task_id}), 201

 

# Route to get all tasks

@app.route('/tasks', methods=['GET'])

def get_tasks():

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("SELECT id, description FROM tasks")

    tasks = cursor.fetchall()

    cursor.close()

    connection.close()

 

    task_list = [{"id": task[0], "description": task[1]} for task in tasks]

    return jsonify(task_list), 200

 

# Route to delete a task by ID

@app.route('/tasks/<int:task_id>', methods=['DELETE'])

def delete_task(task_id):

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("DELETE FROM tasks WHERE id = %s", (task_id,))

    connection.commit()

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task deleted successfully"}), 200

 

if __name__ == "__main__":

    app.run(host='0.0.0.0')

Copy after login
Copy after login
Copy after login
Copy after login

This Dockerfile sets up a lightweight Python environment for a Flask app:

1. Base Image: Uses python:3.9-slim for minimal Python runtime.
Working Directory: Sets /app as the working directory.

2. Dependencies: Copies requirements.txt and installs dependencies via pip.

3. Tool Installation: Installs wait-for-it for checking service readiness.

4. Application Code: Copies all app code into the container.

5. Startup Command: Runs wait-for-it to ensure the MySQL DB (db:3306) is ready before starting app.py.

Requirements.txt File

This requirements.txt specifies that the Python project requires the Flask framework for building web applications and mysql-connector-python for connecting and interacting with a MySQL database. These packages will be installed within the Docker container when pip install -r requirements.txt is run during the image build process. This ensures the app has the necessary tools to run the Flask server and communicate with the MySQL database.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

from flask import Flask, request, jsonify

import mysql.connector

from mysql.connector import Error

 

app = Flask(__name__)

 

# Database connection function

def get_db_connection():

    try:

        connection = mysql.connector.connect(

            host="db",

            user="root",

            password="example",

            database="task_db"

        )

        return connection

    except Error as e:

        return str(e)

 

# Route for the home page

@app.route('/')

def home():

    return "Welcome to the Task Management API! Use /tasks to interact with tasks."

 

# Route to create a new task

@app.route('/tasks', methods=['POST'])

def add_task():

    task_description = request.json.get('description')

    if not task_description:

        return jsonify({"error": "Task description is required"}), 400

 

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("INSERT INTO tasks (description) VALUES (%s)", (task_description,))

    connection.commit()

    task_id = cursor.lastrowid

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task added successfully", "task_id": task_id}), 201

 

# Route to get all tasks

@app.route('/tasks', methods=['GET'])

def get_tasks():

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("SELECT id, description FROM tasks")

    tasks = cursor.fetchall()

    cursor.close()

    connection.close()

 

    task_list = [{"id": task[0], "description": task[1]} for task in tasks]

    return jsonify(task_list), 200

 

# Route to delete a task by ID

@app.route('/tasks/<int:task_id>', methods=['DELETE'])

def delete_task(task_id):

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("DELETE FROM tasks WHERE id = %s", (task_id,))

    connection.commit()

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task deleted successfully"}), 200

 

if __name__ == "__main__":

    app.run(host='0.0.0.0')

Copy after login
Copy after login
Copy after login
Copy after login

After creating all the files the next step is to build and run the service the following command is used to build and run the service.

1

2

3

4

5

6

7

CREATE DATABASE IF NOT EXISTS task_db;

USE task_db;

 

CREATE TABLE IF NOT EXISTS tasks (

    id INT AUTO_INCREMENT PRIMARY KEY,

    description VARCHAR(255) NOT NULL

);

Copy after login
Copy after login
Copy after login

to run the service in a detached mode I used the following command instead of docker-compose up

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

version: '3'

services:

  db:

    image: mysql:5.7

    environment:

      MYSQL_ROOT_PASSWORD: example

      MYSQL_DATABASE: task_db

    ports:

      - "3306:3306"

    volumes:

      - db_data:/var/lib/mysql

      - ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql

 

  web:

    build: .

    ports:

      - "5000:5000"

    depends_on:

      - db

    environment:

      FLASK_ENV: development

    volumes:

      - .:/app

 

volumes:

  db_data:

Copy after login
Copy after login
Copy after login

when I want to stop the service I use the command

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

FROM python:3.9-slim

 

WORKDIR /app

 

# Install dependencies

 

COPY requirements.txt .

RUN pip install -r requirements.txt

 

# Install wait-for-it tool#

 

RUN apt-get update && apt-get install -y wait-for-it

 

#Copy the application code>

 

COPY . .

 

# Use wait-for-it to wait for DB and start the Flask app

 

CMD ["wait-for-it", "db:3306", "--", "python", "app.py"]

Copy after login
Copy after login

Now once the service is in the running state run the command

1

2

Flask

mysql-connector-python

Copy after login

to ensure the containers are running

Now its time to check the service API to ensure they are working as expected.

Testing the Project

Access the app at http://localhost:5000/ .
I was able to access the app on my browser after running the above command as seen in the image below.

Task Manager App with Flask and MySQL

You can use Postman or curl to test the /tasks endpoint for POST, GET, and DELETE operations. In ths case I would be using curl.

curl Commands:

  • Get Tasks:

The GET method fetches all tasks.

1

2

docker-compose build

docker-compose up

Copy after login

Task Manager App with Flask and MySQL

Note that anytime you run http://localhost:5000/tasks on your browser it shows you all the task you have added as explained in the add task.

  • Add a Task:

The POST method creates tasks in the database.

1

docker-compose up -d

Copy after login

This will send a POST request to your Flask app with a task description. If the task is added successfully, you should receive a response like:

1

docker-compose down

Copy after login

check your browser's network tab or logs to verify that the POST request is being made correctly.

I ran the command a couple of times and customized the part where its says Simple Task to generate different outputs here are the commands I ran and the out puts can be seen in the images below.

1

docker ps

Copy after login

Task Manager App with Flask and MySQL

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

from flask import Flask, request, jsonify

import mysql.connector

from mysql.connector import Error

 

app = Flask(__name__)

 

# Database connection function

def get_db_connection():

    try:

        connection = mysql.connector.connect(

            host="db",

            user="root",

            password="example",

            database="task_db"

        )

        return connection

    except Error as e:

        return str(e)

 

# Route for the home page

@app.route('/')

def home():

    return "Welcome to the Task Management API! Use /tasks to interact with tasks."

 

# Route to create a new task

@app.route('/tasks', methods=['POST'])

def add_task():

    task_description = request.json.get('description')

    if not task_description:

        return jsonify({"error": "Task description is required"}), 400

 

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("INSERT INTO tasks (description) VALUES (%s)", (task_description,))

    connection.commit()

    task_id = cursor.lastrowid

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task added successfully", "task_id": task_id}), 201

 

# Route to get all tasks

@app.route('/tasks', methods=['GET'])

def get_tasks():

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("SELECT id, description FROM tasks")

    tasks = cursor.fetchall()

    cursor.close()

    connection.close()

 

    task_list = [{"id": task[0], "description": task[1]} for task in tasks]

    return jsonify(task_list), 200

 

# Route to delete a task by ID

@app.route('/tasks/<int:task_id>', methods=['DELETE'])

def delete_task(task_id):

    connection = get_db_connection()

    if isinstance(connection, str):  # If connection fails

        return jsonify({"error": connection}), 500

 

    cursor = connection.cursor()

    cursor.execute("DELETE FROM tasks WHERE id = %s", (task_id,))

    connection.commit()

    cursor.close()

    connection.close()

 

    return jsonify({"message": "Task deleted successfully"}), 200

 

if __name__ == "__main__":

    app.run(host='0.0.0.0')

Copy after login
Copy after login
Copy after login
Copy after login

Task Manager App with Flask and MySQL

1

2

3

4

5

6

7

CREATE DATABASE IF NOT EXISTS task_db;

USE task_db;

 

CREATE TABLE IF NOT EXISTS tasks (

    id INT AUTO_INCREMENT PRIMARY KEY,

    description VARCHAR(255) NOT NULL

);

Copy after login
Copy after login
Copy after login

Task Manager App with Flask and MySQL

  • Delete a Task:

The DELETE method removes tasks by ID.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

version: '3'

services:

  db:

    image: mysql:5.7

    environment:

      MYSQL_ROOT_PASSWORD: example

      MYSQL_DATABASE: task_db

    ports:

      - "3306:3306"

    volumes:

      - db_data:/var/lib/mysql

      - ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql

 

  web:

    build: .

    ports:

      - "5000:5000"

    depends_on:

      - db

    environment:

      FLASK_ENV: development

    volumes:

      - .:/app

 

volumes:

  db_data:

Copy after login
Copy after login
Copy after login

I ran the below command to remove the task with the ID:4 as seen in the image below task 4 has been removed.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

FROM python:3.9-slim

 

WORKDIR /app

 

# Install dependencies

 

COPY requirements.txt .

RUN pip install -r requirements.txt

 

# Install wait-for-it tool#

 

RUN apt-get update && apt-get install -y wait-for-it

 

#Copy the application code>

 

COPY . .

 

# Use wait-for-it to wait for DB and start the Flask app

 

CMD ["wait-for-it", "db:3306", "--", "python", "app.py"]

Copy after login
Copy after login

Task Manager App with Flask and MySQL

Conclusion

Creating a Task Manager App using Flask and MySQL is an excellent way to understand the fundamentals of web service development, database integration, and containerization with Docker.

This project encapsulates how web servers and databases work in unison to provide seamless functionality.

Embrace this learning experience and use it as a stepping stone to deeper web and cloud-based development projects.

The above is the detailed content of Task Manager App with Flask and MySQL. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? Apr 02, 2025 am 07:15 AM

How to avoid being detected when using FiddlerEverywhere for man-in-the-middle readings When you use FiddlerEverywhere...

How to solve permission issues when using python --version command in Linux terminal? How to solve permission issues when using python --version command in Linux terminal? Apr 02, 2025 am 06:36 AM

Using python in Linux terminal...

How to teach computer novice programming basics in project and problem-driven methods within 10 hours? How to teach computer novice programming basics in project and problem-driven methods within 10 hours? Apr 02, 2025 am 07:18 AM

How to teach computer novice programming basics within 10 hours? If you only have 10 hours to teach computer novice some programming knowledge, what would you choose to teach...

How to get news data bypassing Investing.com's anti-crawler mechanism? How to get news data bypassing Investing.com's anti-crawler mechanism? Apr 02, 2025 am 07:03 AM

Understanding the anti-crawling strategy of Investing.com Many people often try to crawl news data from Investing.com (https://cn.investing.com/news/latest-news)...

Python 3.6 loading pickle file error ModuleNotFoundError: What should I do if I load pickle file '__builtin__'? Python 3.6 loading pickle file error ModuleNotFoundError: What should I do if I load pickle file '__builtin__'? Apr 02, 2025 am 06:27 AM

Loading pickle file in Python 3.6 environment error: ModuleNotFoundError:Nomodulenamed...

What is the reason why pipeline files cannot be written when using Scapy crawler? What is the reason why pipeline files cannot be written when using Scapy crawler? Apr 02, 2025 am 06:45 AM

Discussion on the reasons why pipeline files cannot be written when using Scapy crawlers When learning and using Scapy crawlers for persistent data storage, you may encounter pipeline files...

See all articles