» Python: Build a REST API with Flask » 2. Development » 2.6 Database: MySQL

Database: MySQL

SQLite here is for demonstration only. If you want a more production-ready database, consider using MySQL or mongoDB.

Switch to MySQL

  1. Install MySQL on your machine and start it.

Note: Remember to create indexes on tables based on your need in a production project.

  1. Add mysql dependency:
pip3 install mysql-connector-python

It’s the official MySQL driver written in Python.

Update requirements.txt:

pip3 freeze > requirements.txt
  1. Update code.

Add infrastructure/database/mysql.py:

import mysql.connector
from typing import Any, List, Optional

from books.infrastructure.config import DBConfig

from ...domain.gateway import BookManager
from ...domain.model import Book


class MySQLPersistence(BookManager):
    def __init__(self, c: DBConfig):
        self.conn = mysql.connector.connect(
            host=c.host,
            port=c.port,
            user=c.user,
            password=c.password,
            database=c.database,
            autocommit=True
        )
        self.cursor = self.conn.cursor(dictionary=True)
        self._create_table()

    def _create_table(self):
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS books (
            id INT AUTO_INCREMENT PRIMARY KEY,
            title VARCHAR(255) NOT NULL,
            author VARCHAR(255) NOT NULL,
            published_at DATE NOT NULL,
            description TEXT NOT NULL,
            isbn VARCHAR(15) NOT NULL,
            total_pages INT NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        );
        ''')

    def create_book(self, b: Book) -> int:
        self.cursor.execute('''
            INSERT INTO books (title, author, published_at, description, isbn, total_pages) VALUES (%s, %s, %s, %s, %s, %s)
        ''', (b.title, b.author, b.published_at, b.description, b.isbn, b.total_pages))
        return self.cursor.lastrowid or 0

    def update_book(self, id: int, b: Book) -> None:
        self.cursor.execute('''
            UPDATE books SET title=%s, author=%s, published_at=%s, description=%s, isbn=%s, total_pages=%s WHERE id=%s
        ''', (b.title, b.author, b.published_at, b.description, b.isbn, b.total_pages, id))

    def delete_book(self, id: int) -> None:
        self.cursor.execute('''
            DELETE FROM books WHERE id=%s
        ''', (id,))

    def get_book(self, id: int) -> Optional[Book]:
        self.cursor.execute('''
            SELECT * FROM books WHERE id=%s
        ''', (id,))
        result: Any = self.cursor.fetchone()
        if result is None:
            return None
        return Book(**result)

    def get_books(self) -> List[Book]:
        self.cursor.execute('''
            SELECT * FROM books
        ''')
        results: List[Any] = self.cursor.fetchall()
        return [Book(**result) for result in results]

Notice that the key difference is that we use mysql.connector to replace sqlite3.

Tune infrastructure/database/init.py:

@@ -1 +1,2 @@
 from .sqlite import SQLitePersistence
+from .mysql import MySQLPersistence

Add mysql connection config item into the DBConfig struct in infrastructure/config/config.py:

@@ -4,6 +4,11 @@ from dataclasses import dataclass
 @dataclass
 class DBConfig:
     file_name: str
+    host: str
+    port: int
+    user: str
+    password: str
+    database: str

Update WireHelper to switch the dependency in application/wire_helper.py:

@@ -1,15 +1,15 @@
 from ..domain.gateway import BookManager
 from ..infrastructure.config import Config
-from ..infrastructure.database import SQLitePersistence
+from ..infrastructure.database import MySQLPersistence
 
 
 class WireHelper:
-    def __init__(self, persistence: SQLitePersistence):
+    def __init__(self, persistence: MySQLPersistence):
         self.persistence = persistence
 
     @classmethod
     def new(cls, c: Config):
-        db = SQLitePersistence(c.db.file_name)
+        db = MySQLPersistence(c.db)
         return cls(db)
 
     def book_manager(self) -> BookManager:

Put in mysql connection parammeters in main.py:

@@ -9,7 +9,12 @@ c = Config(
         8080
     ),
     DBConfig(
-        "test.db"
+        "test.db",
+        "127.0.0.1",
+        3306,
+        "test_user",
+        "test_pass",
+        "lr_book"
     )
 )
 wire_helper = WireHelper.new(c)

Voila! Your api server is powered by MySQL now!

PrevNext