Writing an object-oriented MySQLdb connection - python

I am trying to learn OOP, and I am using the database connection via MySQLdb as my first test. This is what I have so far:
class DBConnection:
def __init__(self, DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME):
self.host = DB_HOST
self.port = DB_PORT
self.name = DB_NAME
self.user = DB_USER
self.password = DB_PASSWORD
def get_conn(self):
conn = MySQLdb.connect (host = self.DB_HOST, port = self.DB_PORT,
db = DB_NAME, user = DB_USER,
passwd = DB_PASSWORD)
return conn
def get_cursor(self):
cursor = self.conn.cursor()
return cursor
def get_dict_cursor(self):
dict_cursor = self.conn.cursor(MySQLdb.cursors.DictCursor)
return dict_cursor
Is the above valid? Does self.conn refer to get_conn() or is this an invalid reference. How would I establish a connection to the database and then get a cursor, using the python shell?

You haven't defined self.conn anywhere. You're only setting conn as a local inside of get_conn. Define self.conn in your constructor, and then update get_conn to set self.conn. Like this:
class DBConnection:
def __init__(self, DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME):
self.host = DB_HOST
self.port = DB_PORT
self.name = DB_NAME
self.user = DB_USER
self.password = DB_PASSWORD
self.conn = None
def get_conn(self):
self.conn = MySQLdb.connect(host = self.host,
port = self.port,
db = self.name,
user = self.user,
passwd = self.password)
Also, check whether self.conn is set first as opposed to creating a new one each time in get_conn, like this:
def get_conn(self):
if self.conn is None:
self.conn = MySQLdb.connect(host = self.host,
port = self.port,
db = self.name,
user = self.user,
passwd = self.password)
return self.conn
Finally, call the get_conn method like this:
mydbconnobj = DBConnection('localhost',3306,'foouser','foopass','foodbname')
mydbconn = mydbconnobj.get_conn()

Related

How connect to database and get data via python like in R

I new in python. I need connect to mysql database and get data. Before that, I easily took data via R using rodbslike this.
library(DBI)
library(RMySQL)
db_user = 'k'
db_password = 'F6'
db_name = 'meg'
db_table = 'dat'
db_host = 'my.g2s' # for local access
db_port = 3306
# 3. Read data from db
mydbV7 = dbConnect(MySQL(), user = db_user, password = db_password,
dbname = db_name, host = db_host, port = db_port)
sV7 = paste0("select * from ", db_table)
rsV7 = dbSendQuery(mydbV7, sV7)
df = fetch(rsV7, n = -1)
but when i tried to implement the same principle in python i get errors
import pyodbc
>>> db_user = 'k'
>>> db_password = 'F6'
>>> db_name = 'meg'
>>> db_table = 'dat'
>>> db_host = 'my.g2s' # for local access
>>> db_port = 3306
>>> mydbV7 = dbConnect(MySQL(), user = db_user, password = db_password,
... dbname = db_name, host = db_host, port = db_port)
File "<stdin>", line 2
... dbname = db_name, host = db_host, port = db_port)
^
SyntaxError: positional argument follows keyword argument
How can i correct get data via python 3.9?
As always, I appreciate any of your help.
As describe in the MySQL documentation, you can import mysql.connector and then use :
cnx = mysql.connector.connect(user = 'scott',
password = 'password',
host = '127.0.0.1',
database = 'employees')
Of course, you have to change the values with yours.
cnx will then represent the connection with your database.

AttributeError: 'NoneType' object has no attribute 'fetchall'

I tried to return the result of an SQL query.
This works perfectly with pyodbc but not with mysql-connector.
Error Output
File "/mySQLDB.py", line 17, in execute_and_fetch
result = conn.cursor().execute(query, params).fetchall()
AttributeError: 'NoneType' object has no attribute 'fetchall'
Code
import mysql.connector
class MYSQLDB:
def __init__(self):
self.host = 'xx'
self.database = 'xx$xx'
self.user = 'xx'
self.password = 'xx'
def execute(self, query, *params):
mysql.connector.connect(host=self.host, database=self.database,
user=self.user, password=self.password).cursor().execute(query, params).commit()
def execute_and_fetch(self, query, *params):
conn = mysql.connector.connect(host=self.host, database=self.database,
user=self.user, password=self.password)
result = conn.cursor().execute(query, params).fetchall()
conn.commit()
return result
PEP 249, the DBAPI spec, says that the return value of execute is undefined. Quite a few DBAPI implementations return None, meaning that you cannot (portably) chain execute().fetchall() as you are trying to do.
Try this code.
If you are still having problems check that the connection to the database is successful.
import mysql.connector
class MYSQLDB:
def __init__(self):
self.host = 'xx'
self.database = 'xx$xx'
self.user = 'xx'
self.password = 'xx'
def execute(self, query, *params):
mysql.connector.connect(host=self.host, database=self.database,
user=self.user, password=self.password).cursor().execute(query, params).commit()
def execute_and_fetch(self, query, *params):
conn = mysql.connector.connect(host=self.host, database=self.database,
user=self.user, password=self.password)
with conn.cursor() as cursor:
cursor.execute(query, params=None)
... result = cursor.fetchall()
conn.commit()
return result

How to modularize a code containing 'with' in Python

I have this code that I am using to get information from a mysql database
def query_result_connect(_query):
with SSHTunnelForwarder((ssh_host, ssh_port),
ssh_password=ssh_password,
ssh_username=ssh_user,
remote_bind_address=('127.0.0.1', 3306)) as server:
connection = mdb.connect(user=sql_username,
passwd=sql_password,
db=sql_main_database,
host='127.0.0.1',
port=server.local_bind_port)
cursor = connection.cursor()
cursor.execute(_query)
connection.commit()
try:
y = pd.read_sql(_query, connection)
return y
except TypeError as e:
x = cursor.fetchall()
return x
I would like to create a function that includes the following part.
with SSHTunnelForwarder((ssh_host, ssh_port),
ssh_password=ssh_password,
ssh_username=ssh_user,
remote_bind_address=('127.0.0.1', 3306)) as server:
connection = mdb.connect(user=sql_username,
passwd=sql_password,
db=sql_main_database,
host='127.0.0.1',
port=server.local_bind_port)
and execute it in the query_result_connect() function. The problem is that I don't know how to include more code within the 'with' statement. The code should look something like this:
# Maybe introduce some arguments
def db_connection():
with SSHTunnelForwarder((ssh_host, ssh_port),
ssh_password=ssh_password,
ssh_username=ssh_user,
remote_bind_address=('127.0.0.1', 3306)) as server:
connection = mdb.connect(user=sql_username,
passwd=sql_password,
db=sql_main_database,
host='127.0.0.1',
port=server.local_bind_port)
# Maybe return something
def query_result_connect(_query):
# call the db_connection() function somehow.
# Write the following code in a way that is within the 'with' statement of the db_connection() function.
cursor = connection.cursor()
cursor.execute(_query)
connection.commit()
try:
y = pd.read_sql(_query, connection)
return y
except TypeError as e:
x = cursor.fetchall()
return x
Thank you
What's about to make "do_connection" to be a context manager itself?
#contextmanager
def do_connection():
# prepare connection
# yield connection
# close connection (__exit__). Perhaps you even want to call "commit" here.
Then, you will use it like this:
with do_connection() as connection:
cursor = connection.cursor()
...
It is a common approach to use context managers for creating DB connections.
You could make you own Connection class, that works like a conext manager.
__enter__ sets up ssh tunnel and db connection.
__exit__, tries to close the cursor, db connection and the ssh tunnel.
from sshtunnel import SSHTunnelForwarder
import psycopg2, traceback
class MyDatabaseConnection:
def __init__(self):
self.ssh_host = '...'
self.ssh_port = 22
self.ssh_user = '...'
self.ssh_password = '...'
self.local_db_port = 59059
def _connect_db(self, dsn):
try:
self.con = psycopg2.connect(dsn)
self.cur = self.con.cursor()
except:
traceback.print_exc()
def _create_tunnel(self):
try:
self.tunnel = SSHTunnelForwarder(
(self.ssh_host, self.ssh_port),
ssh_password=self.ssh_password,
ssh_username=self.ssh_user,
remote_bind_address=('localhost', 5959),
local_bind_address=('localhost', self.local_db_port)
)
self.tunnel.start()
if self.tunnel.local_bind_port == self.local_db_port:
return True
except:
traceback.print_exc()
def __enter__(self):
if self._create_tunnel():
self._connect_db(
"dbname=mf port=%s host='localhost' user=mf_usr" %
self.local_db_port
)
return self
def __exit__(self, *args):
for c in ('cur', 'con', 'tunnel'):
try:
obj = getattr(self, c)
obj.close()
obj = None
del obj
except:
pass
with MyDatabaseConnection() as db:
print(db)
db.cur.execute('Select count(*) from platforms')
print(db.cur.fetchone())
Out:
<__main__.MyDatabaseConnection object at 0x1017cb6d0>
(8,)
Note:
I am connecting to Postgres, but that should work using mysql as well. Probably you need to adjust to match your own needs.

Python 2.7 connection string to PostgreSQL (OOP method)

I'm new to python and I'm trying to make this work. I'm using Python 2.7 and PostgreSQL 9.3:
#! F:\Python2.7.6\python
import psycopg2
class Database:
host = "192.168.56.101"
user = "testuser"
passwd = "passwd"
db = "test"
def __init__(self):
self.connection = psycopg2.connect( host = self.host,
user = self.user,
password = self.passwd,
dbname = self.db )
self.cursor = self.connection.cursor
def query(self, q):
cursor = self.cursor
cursor.execute(q)
return cursor.fetchall()
def __del__(self):
self.connection.close()
if __name__ == "__main__":
db = Database()
q = "DELETE FROM testschema.test"
db.query(q)
However I am getting an error "AttributeError: 'builtin_function_or_method' object has no attribute 'execute'". I figure I should put something like self.execute = something in the Database class, but I can't figure it out what exactly I need to put there. Any suggestions?
You are missing the parenthesis at the end
self.cursor = self.connection.cursor()
or
cursor = self.cursor()
But not both

Python re-connecting to MySQLdb

I have the following:
class DBConnection:
def __init__(self, DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME):
self.host = DB_HOST
self.port = DB_PORT
self.name = DB_NAME
self.user = DB_USER
self.password = DB_PASSWORD
self.conn = None
self.cursor = None
def get_conn(self):
if self.conn is None:
self.conn = MySQLdb.connect (host = self.host, port = self.port, db = self.name, user = self.user, passwd = self.password)
return self.conn
def close_conn(self):
if self.conn:
self.conn.close()
return self.conn
This is what it looks like when I try and reconnect:
>>> from db_conn import DBConnection
>>> db = DBConnection(DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME)
>>> db.get_conn()
<_mysql.connection open to '127.0.0.1' at 7fbb1b8a2420>
>>> db.close_conn()
>>> db.conn
<_mysql.connection closed at 7fbb1b8a2420>
>>> db.get_conn()
<_mysql.connection closed at 7fbb1b8a2420>
Why won't it allow me to re-open the connection? How would I re-open it, or do I need to create a new instance?
You're testing whether self.conn is 'None' but it's not - it's still a mysql connection object. One of its properties or methods will tell you whether it's open or not, so you could test that instead, or set self.conn to None in close_conn if that's easier.
The function "close_conn" return self_conn after it colseed connection. So the virable self_conn always be true, right?

Categories