Search code examples
pythonmysqldatabasemysql-connector-python

Python - accessing single database wrapper object from multiple objects


I have a simple Python wrapper around a MySQL database, and I need to be able to access it from inside other custom class objects within Python. The wrapper class lives in a separate file to each of the other custom classes. So far I've only been able to find the following ways of doing things:

  1. Make the database object global (bad)
  2. Pass the database object into every other object's constructor (inelegant)
  3. Stop using the database wrapper class entirely (annoying)

There must surely be a better way of doing this in Python (yes, I have searched the web and Stack Overflow, but apparently I'm searching for the wrong keywords). Can anyone explain what it is? I only need one database connection, and most of my other classes need to use it. Dummy Python code explaining the sort of thing I'm trying to do follows.

(Partial) Database wrapper class:

import mysql.connector

class Database:

    def __init__( self, username, password, database, host = 'localhost' ):
        self.connection = mysql.connector.connect( user = username, password = password, database = database, host = host )
        self.connection.set_autocommit( True )
        self.cursor = self.connection.cursor( dictionary = True )

    def __del__( self ):
        self.cursor.close()
        self.connection.close()

    def fetchAll( self, query, constraints = None ):
        self.cursor.execute( query, constraints )
        return self.cursor.fetchall()

    def delete( self, id, table, key = 'id' ):
        self.cursor.execute( 'DELETE FROM `' + table + '` WHERE `' + key + '` = %s', ( id, ) )

Another class requiring access to the database (N.B. undeclared object db in class methods):

class Queue:
    def __init__( self ):
        self.jobs = []

    def refreshJobs( self ):
        self.jobs = db.fetchAll( 'SELECT * FROM `jobs`' )

    def deleteJob( self, id ):
        db.delete( id, 'jobs' )
        self.refreshJobs()

A third class that accesses the database (N.B. undeclared object db in class methods):

class User:
    def __init__( self, email ):
        self.email = email
        details = db.fetchAll( 'SELECT * FROM `users` WHERE `email` = %s', [email] )
        if( len( details ) == 1 ):
            self.password = details[0]['password']

Any suggestions much appreciated, except framework recommendations. I'd really like to deepen my understanding of how best to handle this sort of situation in Python. Thanks in advance!


Solution

  • Answering my own question since no one responded, and this might be useful to other people in future. I was recommended to use a "half-way" global, by writing an intermediary module that looks something like this:

    from my_db_class import Database
    db = Database( 'user', 'password', 'database' )
    

    Then in Queue and User classes, do something like this:

    from my_db_instantiation import db
    

    You can then access the same db database object in each of the classes that requires it. Note that only my_db_intermediary imports my_db_class directly. All other modules import my_db_intermediary. It might seem a bit convoluted but it allows you to keep your class implementations separate from the parameters required to instantiate them, in this case the database class and its associated credentials.