Python: Create a class for SQL select and update statement - python

Is there any other way to improve this code? I'm trying to create a class with select and update method then I call it for future use.
connect.py
import pymysql
class SQL:
def __init__(self):
self.cnx = pymysql.connect(host...)
self.c = self.cnx.cursor()
def select(self, sql):
self.c.execute(sql)
self.sel = self.c.fetchone()
self.c.close()
self.cnx.close()
return self.sel
def update(self, sql):
self.c.execute(sql)
self.upd = self.cnx.commit()
self.c.close()
self.cnx.close()
return self.upd
from connect import SQL
stmt = "SELECT * FROM name;"
result = SQL().select(stmt)

import pymysql
class Connection:
def __init__(self):
self.con = pymysql.connect(
host = 'localhost',
port = 3306,
user = 'user',
password = 'password',
db = 'dbname',
autocommit=True,
charset = 'utf8mb4',
cursorclass = pymysql.cursors.DictCursor
)
self.cur = self.con.cursor()
def _select(self,sql,args=None):
self.cur.execute(sql,args)
self.sel = self.cur.fetchone()
self.cur.close()
self.con.close()
return self.sel
def _selectAll(self,sql,args=None):
self.cur.execute(sql,args)
self.sel = self.cur.fetchall()
self.cur.close()
self.con.close()
return self.sel
def _insert(self,sql,args=None):
self.ins = self.cur.executemany(sql,args)
return self.ins
def _update(self,sql, args=None):
self.upd = self.cur.executemany(sql,args)
return self.upd
def _delete(self, sql, args=None):
self.delete = self.cur.executemany(sql,args)
return self.delete
I used a logic to repository creating this class, an example(with PyPika) of use is this:
from foo.bar import Connection
from pypika import Query, Table
users = Table("users")
class UserRepository(Connection):
def getById(self, args=None):
query = Query.from_(users).select("*").where(users.tg_id == "%s")
q = query.get_sql(quote_char=None)
return self._select(q, args)
And now an example of how to invoke the repository:
from foo.bar import UserRepository
def init(user):
row = UserRepository().getById(user)
for i in row:
print(i)

Add a function in this class ,function close().use close() in the end of the main().Besides ,use try and except in your every function. Also you can add a reinit function to be called in every function.

Related

I want to specify the class (type) of the parameter

class PostgreSql():
def __init__(self):
pass
class User():
def __init__(self):
pass
def set_dsn(self, connects_database: bool):
self.dsn = "host={host} user={user} password={password} port={port}".format(
host=self.host,
user=self.user,
password=self.password,
port=self.port,
)
if connects_database==True:
self.dsn = "{dsn} {database}".format(
dsn=self.dsn,
database=self.database
)
def set_host(self, host: str):
self.host = host
def set_user(self, user: str, password: str):
self.user = user
self.password = password
def set_port(self, port: str):
self.port = port
def set_database(self, database: str):
self.database = database
class Session():
def __init__(self):
pass
def connect(self, dsn: str):
self.con = psycopg2.connect(dsn=dsn)
self.cur = self.con.cursor()
def create_database(self, name: str):
query = SQL("CREATE DATABASE {name}").format(name=Identifier(name))
try:
self.cur.execute(query=query)
except DuplicateDatabase:
print("{name} Database Already Created.".format(name=name))
else:
print("{name} Database Create.".format(name=name))
def create_table(self, name: str, coulmn: str):
"""This function is create new table in database of instance connection.
Args:
name : Name of the table to be created.
coulmn : Column in the table to be created.
Format is "(name data_type condition, name2 data_type2 condition2...)".
"""
self.cur.execute(
query=SQL("CREATE TABLE {name} %s;").format(name=Identifier(name)),
vars=[coulmn]
)
def create_tables(self, names: list, coulmn: str):
"""This function is create new tables in database of instance connection.
Args:
names : Names of the table to be created.
coulmn : Column in the table to be created.
Format is "(name data_type condition, name2 data_type2 condition2...)".
"""
for name in names:
self.cur.execute(
query=SQL("CREATE TABLE {name} %s;").format(name=Identifier(name)),
vars=[coulmn]
)
full code
def connect(self, dsn: str):
self.con = psycopg2.connect(dsn=dsn)
self.cur = self.con.cursor()
This is the source of the code I want to change.
def connect(self, dsn: User):
self.con = psycopg2.connect(dsn=User.dsn)
self.cur = self.con.cursor()
I want the connect function to take a user class as a parameter, not a simple string class, and refer to the dsn of the user class.
However, the User class does not appear in the visual studio code, so it cannot be specified.
Reference Image
Why can't the connect function read the User class?
you should be calling the class from its parent class :
def connect(self, dsn: PostgreSql.User):
self.con = psycopg2.connect(dsn=User.dsn)
self.cur = self.con.cursor()
and you should import annotations:
from __future__ import annotations

SQLAlchemy: execute() got an unexpected keyword argument

I have database.py which contains the database exec functions
import sqlachemy
class DB():
def __init__(self, **kwargs):
self.connection = None
self.connect(**kwargs)
def connect(self, **kwargs):
if 'url' in kwargs and kwargs.get('url') is not None:
return self.connectUrl(kwargs.get('url'), kwargs.get('username'),
kwargs.get('password'), kwargs.get('database'))
else :
return self.connectHost(kwargs.get('host'), kwargs.get('port'), kwargs.get('username'),
kwargs.get('password'), kwargs.get('database'))
def execute(self, query):
if self.connect is None:
raise Exception('No connection')
try:
with self.connection.connect() as conn:
return conn.execute(query)
except (pymysql.err.OperationalError, sqlalchemy.exc.OperationalError) as e:
print(e)
except (Exception) as e:
print(e)
else:
return None
Also I've a main.py. Im importing the DB class from the above file and using it here.
from database import db
# db connection
def connect():
global db
db = DB(
database="DATABASE_NAME",
username="DATABASE_USER",
password="XXXXXXXXX",
url="XXXXXXX",
host="XXXXXXXXXXX",
port="XXXXXXX",
)
SQL_QUERY = """ select * from sample_table where country = :country and age = :age """
_age = 5
_country = 'US'
connect()
query = text(SQL_QUERY).bindparams(bindparam("country", String), bindparam("age", String))
db.execute(query, age=_age, country=_country)
When I'm trying to execute this script, I'm getting an error
db.execute(query,age=_age, country=_country) TypeError: execute() got an unexpected keyword argument 'age'
Can anyone help me with this?
you can simply pass variables as tuple :
query = 'select * from sample_table where country = ? and age = ?'
_age = 5
_country = 'US'
connect()
db.execute(query, (_age,_country,))

what is the best creational pattern to apply for class to access different databases

i have an application written in python
currently there are around 5 classes that are used to access different databases.
Structure of these classes are like below (i know it is poorly designed):
class access_db_a:
def __init__(self, db):
self.mydb = None
def connect(self):
mydb = mysql.connector.connect(
host=info["db_2_host"],
user=info["user"],
passwd=info["passwd"],
database=info["db_2"],
)
def select(self):
mycursor = mydb.cursor()
mycursor.execute("SELECT * FROM {}".format(TABLE_NAME))
myresult = mycursor.fetchall()
for x in myresult:
print(x)
def insert(self):
mycursor = mydb.cursor()
query = {'queries for db'}
class access_db_b:
def __init__(self, db_2):
self.mydb = None
def connect(self, db_2):
mydb = mysql.connector.connect(
host=info["db_2_host"],
user=info["user"],
passwd=info["passwd"],
database=info["db_2"],
)
def select(self):
mycursor = mydb.cursor()
mycursor.execute("SELECT * FROM {}".format(TABLE_NAME))
myresult = mycursor.fetchall()
for x in myresult:
print(x)
def insert(self):
mycursor = mydb.cursor()
query = {'queries for db_2'}
My question is: what is the best creational design pattern to apply here (i.e. Signleton, Factory Method)? the purpose is to minimize the duplication
You might want to define a base class for mysql. This class can be separated in a file, maybe as your own library.
class mysqlBase():
def __init__(self, host, user, passwd, database):
self.host = host
self.user = user
self.passwd = passwd
self.database = database
self.db = None
def connect(self,):
self.db = mysql.connector.connect(
host = self.host,
user = self.user,
passwd = self.passwd,
database = self.database,
)
def select(self, tbl):
mycursor = self.db.cursor()
mycursor.execute("SELECT * FROM {}".format(tbl))
myresult = mycursor.fetchall()
for x in myresult:
print(x)
# more functions
# ...
then use it in your classes
class access_db_a():
def __init__(self, host, user, passwd, database):
self.mydb = mysqlBase(host, user, passwd, database)
def connect(self,):
self.mydb.connect()
def select(self, tbl):
self.mydb.select(tbl)
# more functions refer to mysqlBase()
# ...
or with class inheritance,
class access_db_a(
mysqlBase
):
def __init__(self, host, user, passwd, database):
mysqlBase.__init__(self, host, user, passwd, database)
# No need to define connect(), unless you wanna override it
# No need to define select(), unless you wanna override it
finally, in your code, call your class as object.
# Const
info = { # just some database const
'A': {
"host": "192.128.0.123",
"id": "AAA",
"pw": "aaa",
"db": "whatever",
},
}
dbA = access_db_a(**info['A']) # pass the login detail to your class
dbA.connect()
dbA.select('TABLE_A')
I'm not sure I understand what you are asking. If you are trying to call those definitions on the databases, you need to define them. As is they don't do anything. If they are functions that already exist in the python library or another module, then you don't need to put them in a class at all. You can just call them on the databases after you define them.
I'm not sure I understand what you are asking. If you are trying to call those definitions on the databases, you need to define them. As is they don't do anything. If they are functions that already exist in the python library or another module, then you don't need to put them in a class at all. You can just call them on the databases after you define them.
Also, if you are trying to make the functions to be attributes of the class, then you need an __init__() constructor function. like this:
class access_db_a():
def __init__(self):
self.connect = connect()
self.select = select()
self.insert = insert()

Library program in Python 3 (beginner) with psycopg2

I need help with this program. I am making a program for a library in Python 3 (psycopg2) and I am making my modules to handle my tables, I have already done the "create" module and I am doing the "delete" module, I need help to do it, the code used is the following:
This is my class ConnectioDB: (it works to connect to my database in postgresql)
class ConnectionDB:
"""Connection class."""
bd = None
cursor = None
def __init__(self, **param):
"""Connection constructor."""
try:
self.db = connect(
host = '127.0.0.1', # localhost
user = 'postgres'
password = #$#!#*
database = 'national-library'
)
self.cursor = self.db.cursor()
except Error as e:
write_errors(e, 'Failed to connect to database')
with the following lines are used to execute sql code:
def execute_sql(
self,
sentence_sql,
param=None,
write_in_db=True
):
"""Execute SQL code."""
try:
execute = self.cursor.execute(sentence_sql, param)
if write_in_db:
result = self.db.commit()
except Exception as e:
write_errors(e, f"An error occurred while executing the SQL statement:\n\n{sentence_sql}\n")
if write_in_db:
self.db.rollback()
now this is my Model class that has the "create" module
class Model():
"""Generic model class."""
table_name = None
connection = ConnectionDB()
def create(self):
"""Save in database."""
table_name = self.table_name
keys = ", ".join(self.__dict__.keys())
values_placeholders = ", ".join(["%s" for i in range(len(self.__dict__.keys()))])
values = self.__dict__.values()
sql = f"INSERT INTO {table_name} ({keys}) VALUES ({values_placeholders})"
self.connection.execute_sql(sql, tuple(values))
I was trying to do the following code for my "delete" module but I'm not sure if it's ok:
def delete(self, column_id):
"""Delete an item in the database."""
table_name = self.table_name
sql = f"DELETE FROM {table_name} WHERE id = %s"
self.connection.execute_sql(sql, (column_id, ))
I hope you can help me. Thank you!

Use decorator to connect to a postgres database

I am working on a program to store my picture meta data and thumbnails into a postgres database using python and psycopg2. In the example I have defined a class MyDbase with methods to create a table, store a value and load a value. Each of these methods needs to connect to the database and a cursor object to execute sql commands. To avoid repetition of code to make the connection and get the cursor I have made a sub class DbDecorators with a decorator connect.
My question: is this a proper way to handle this and specifically using the with statement and passing the cursor to the Dbase method (func) inside the wrapper?
from functools import wraps
import psycopg2
class MyDbase:
''' example using a decorator to connect to a dbase
'''
table_name = 'my_table'
class DbDecorators:
host = 'localhost'
db_user = 'db_tester'
db_user_pw = 'db_tester_pw'
database = 'my_database'
#classmethod
def connect(cls, func):
#wraps(func)
def wrapper(*args, **kwargs):
connect_string = f'host=\'{cls.host}\' dbname=\'{cls.database}\''\
f'user=\'{cls.db_user}\' password=\'{cls.db_user_pw}\''
result = None
try:
with psycopg2.connect(connect_string) as connection:
cursor = connection.cursor()
result = func(*args, cursor, **kwargs)
except psycopg2.Error as error:
print(f'error while connect to PostgreSQL {cls.database}: '
f'{error}')
finally:
if connection:
cursor.close()
connection.close()
print(f'PostgreSQL connection to {cls.database} is closed')
return result
return wrapper
#staticmethod
def get_cursor(cursor):
if cursor:
return cursor
else:
print(f'no connection to database')
raise()
#classmethod
#DbDecorators.connect
def create_table(cls, *args):
cursor = cls.DbDecorators().get_cursor(*args)
sql_string = f'CREATE TABLE {cls.table_name} '\
f'(id SERIAL PRIMARY KEY, name VARCHAR(30));'
print(sql_string)
cursor.execute(sql_string)
#classmethod
#DbDecorators.connect
def store_value(cls, name, *args):
cursor = cls.DbDecorators().get_cursor(*args)
sql_string = f'INSERT INTO {cls.table_name} (name) VALUES (%s);'
print(sql_string)
cursor.execute(sql_string, (name,))
#classmethod
#DbDecorators.connect
def load_value(cls, _id, *args):
cursor = cls.DbDecorators().get_cursor(*args)
sql_string = f'SELECT * FROM {cls.table_name} where id = \'{_id}\';'
print(sql_string)
cursor.execute(sql_string)
db_row = cursor.fetchone()
return db_row
def test():
my_db = MyDbase()
my_db.create_table()
my_db.store_value('John Dean')
db_row = my_db.load_value(1)
print(f'id: {db_row[0]}, name: {db_row[1]}')
if __name__ == '__main__':
test()
probably I did not get your request correctly. Why you need decorator but don't use context manager? Like define db client in any file where from you can import it later and then use it in context manager –
from psycopg2 import SomeDataBase
db = SomeDataBase(credentials)
def create_table(table_name):
with db:
sql_string = f'CREATE TABLE {table_name} '\
f'(id SERIAL PRIMARY KEY, name VARCHAR(30));'
db.cursor.execute(sql_string)
Using a context manager will not close the connection, only the cursor. So using the decorator pattern actually makes more sense here. More info on the context manager: https://www.psycopg.org/docs/usage.html (scroll down to the "with statement" section.)

Categories

Resources