What is the most pythonic way/trick to support two database backends and keep my code DRY?

StackOverflow https://stackoverflow.com/questions/19291056

  •  30-06-2022
  •  | 
  •  

Вопрос

I have the following example code which uses either MongoEngine and Peewee as DB backends.

import mongoengine, peewee
from mongomodels import *
from mysqlmodels import *

class Parser(object):

    def __init__(self, line, dbBackend):
        if dbBackend in ["MongoDB","MySQL"]:
            self.line = line
            self.DB = dbBackend
            user = self.createUser()
            car = self.createCar(user)
            parking = self.createParking(car)
        else:
            raise Exception()

    def createUser(self):
        if self.DB == "MongoDB":
            newUserID = self._createMongoUser(self.line['firstname'], self.line['lastname'], '...')
        else:
            newUserID = self._createMySQLUser(self.line['firstname'], self.line['lastname'], '...')

        return newUserID

    def _createMongoUser(self, firstname, lastname, '...'):
        try:
            _user = MongoUserModel.objects.get(firstname=firstname, lastname=lastname)
        except mongoengine.errors.DoesNotExist as e:
            user = MongoUserModel(firstname=firstname, password)
            _user = user.save()
        finally:
            return _user



    def _createMySQLUser(self, firstname, lastname, '...'):
        try:
            _user = MySQLUserModel.get(MySQLUserModel.fistname == firstname, MySQLUserModel.lastname == lastname )
        except Exception as e:
            user = MySQLUserModel(fistname=fistname, lastname=lastname)
            _user = user.save()
        finally:
            return _user


    def createCar(self, user):
        pass

    def createParking(self, car):
        pass

Is there any good practice / trick / module to keep my code DRY and to avoid redefining two methods to create my Models?

Should I can create a new abstraction class 'UserModel' as does PDO in PHP?

Это было полезно?

Решение

This is something I went through recently - I swapped from a mongo backend to postgres. When I set up the original project I had some models and a DataLayer. The datalayer (dl) had quite a simple interface that I used throughout my app.

# note: this is half python / half pseudocode

class Model1(object):
    __collection__ = 'model1'
    __tablename__ = 'model1'
    # field definitions etc


class MongoDataLayer(object):
    def __init__(self, mongo_db_connection):
        self.conn = mongo_db_connection

    def load(self, model, conditions):
        raw = self.conn[model.__collection__].find(...)
        return model(**raw)

    def persist(self, obj):
        self.conn[obj.__collection__].save(obj.as_dict())


class SQLDataLayer(object):
    def __init__(self, sa_session_factory):
        self.Session = sa_session_factory
        self.session = self.Session()

    def load(self, model, conditions):
        return self.session.query(model).find_by(conditions).one() # ...etc

    def persist(self, obj):
        self.conn[obj.__collection__].save(obj)

# connections - mongo and postgres (I use SQLAlchemy)
dl_mongo = MongoDataLayer(db...)
dl_sql = SQLDataLayer(Session...)

# using them - you don't care which one you have
m = dl_mongo.load(models.Model1)
dl_mongo.persist(m)

m = dl_sql.load(models.Model1)
dl_sql.persist(m)

In my app I load up the dl in the initial load and then inject it into the app whenever data access needs to happen. The app itself then knows about models but not the details of how to load / save them.

Maybe not the best way to do it but it's worked well for me. Would be interested to hear how other people deal with it.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top