Whenever I write some code in python that involves a MySQL database, I use this base class that contains all the generic code for the basic CRUD operations. This allows me to focus on writing the queries instead of writing the same boilerplate code every time. It uses the client library PyMySQL and will take care of opening and disposing the connections to the database as well as preventing SQL injection by using parameterized queries. Just wanted to share it so that others can use it too.
Methods
__execute
and __openConnection
are private methods used internally in the class.
execute
is intended for insert, update and delete statements and returns the number of affected rows in the table.
select_all
is for select statements and returns a list of the rows that satisfy the query condition(s).
select_one
is also for select statements and returns the first row that satisfies the query condition(s).
import pymysql.cursors
class SqlBase(object):
def __init__(self, host, user, password, database):
self.host = host
self.user = user
self.password = password
self.database = database
def execute(self, query:str, parameters:list=[]):
return self.__execute(query, parameters).rowcount
def select_all(self, query:str, parameters:list=[]):
cursor = self.__execute(query, parameters)
return cursor.fetchall()
def select_one(self, query:str, parameters:list=[]):
cursor = self.__execute(query, parameters)
return cursor.fetchone()
def __execute(self, query:str, parameters:list=[]):
try:
with self.__openConnection() as connection:
with connection.cursor() as cursor:
cursor.execute(query, parameters)
connection.commit()
return cursor
except pymysql.Error as e:
print(f"Error while executing query [{query}]: {str(e)}")
def __openConnection(self):
try:
return pymysql.connect(host=self.host, user=self.user, password=self.password, database=self.database, cursorclass=pymysql.cursors.DictCursor)
except pymysql.Error as e:
print(f"Error while opening sql connection: {str(e)}")
Example
Create a class that inherits the SqlBase
class and call the base constructor with the database credentials. In this example I have made a user repository with examples of the CRUD operations by using execute
, select_one
and select_all
. Notice how the values are parsed as a separate list of parameters rather than being inserted directly into the query itself. This is very important in order to avoid SQL injection attacks in case the values comes from user input like query parameters.
from sql_base import SqlBase
class UserRepository(SqlBase):
def __init__(self):
SqlBase.__init__(self, "host", "user", "password", "database")
def insert(self, username, email):
query = "INSERT INTO users(username, email) VALUES (%s,%s)"
return self.execute(query, [username, email])
def get(self, username):
query = "SELECT id, username, email FROM users WHERE username=%s"
return self.select_one(query, [username])
def get_all(self):
query = "SELECT id, username, email FROM users"
return self.select_all(query)
def update(self, username, email):
query = "UPDATE users SET email=%s WHERE username=%s"
return self.execute(query, [email, username])
def delete(self, username):
query = "DELETE FROM users WHERE username=%s"
return self.execute(query, [username])