SQLAlchemy - 映射一个类到两个表

问题描述:

我有两个数据库队列的实现(他们使用不同的表),并希望他们使用同一类的对象。所以,他们都看起来很类似:SQLAlchemy - 映射一个类到两个表

class AbstractDBQueue(object): 
    def __init__(self, tablename): 
     self.tablename = tablename 
     self.metadata = MetaData() 
     self.engine = create_engine('mysql+mysqldb://%s:%[email protected]%s:%d/%s' % (
      settings.DATABASE.get('USER'), 
      settings.DATABASE.get('PASSWORD'), 
      settings.DATABASE.get('HOST') or '127.0.0.1', 
      settings.DATABASE.get('PORT') or 3306, 
      settings.DATABASE.get('NAME') 
     ), encoding='cp1251', echo=True, pool_recycle=7200) 
     self.metadata.bind = self.engine 
     self.session = sessionmaker(bind=self.engine)() 

    def setup_table(self, table, entity_name): 
     self.table = table 
     newcls = type(entity_name, (SMSMessage,), {}) 
     mapper(newcls, table) 
     return newcls 

    def put(self, message=None, many_messages=[]): 
     if message: 
      self.session.add(message) 
     else: 
      for m in many_messages: 
       self.session.add(m) 
     self.session.commit() 

    def get(self, limit=None): 
     if limit: 
      q = self.session.query(self.SMSClass).limit(limit) 
     else: 
      q = self.session.query(self.SMSClass) 
     smslist = [] 
     for sms in q: 
      smslist.append(sms) 
     self.session.expunge_all() 
     return smslist 

class DBQueue(AbstractDBQueue): 
    """ 
    MySQL database driver with queue interface 
    """ 
    def __init__(self): 
     self.tablename = settings.DATABASE.get('QUEUE_TABLE') 
     super(DBQueue, self).__init__(self.tablename) 
     self.logger = logging.getLogger('DBQueue') 
     self.SMSClass = self.setup_table(Table(self.tablename, self.metadata, autoload=True), "SMSQueue") 

class DBWorkerQueue(AbstractDBQueue): 
    """ 
    MySQL database driver with queue interface for separate workers queue 
    """ 

    def __init__(self): 
     self.tablename = settings.DATABASE.get('WORKER_TABLE') 
     super(DBWorkerQueue, self).__init__(self.tablename) 
     self.logger = logging.getLogger('DBQueue') 
     self.SMSClass = self.setup_table(Table(self.tablename, self.metadata, autoload=True), "SMSWorkerQueue") 

    def _install(self): 
     self.metadata.create_all(self.engine) 

SMSMessage是我想使用的类的名称。该map_class_to_table()功能是一个黑客,我SQLAlchemy的文档中找到:http://www.sqlalchemy.org/trac/wiki/UsageRecipes/EntityName

不过,这并不似乎帮助 - 当第一个队列实例映射SMSMessage到它的表,然后我通过所有对象到第二个队列的put()被隐式转换为第一个队列的映射类,第二个数据库在session.commit()后仍然为空。

我需要同时使用这两个队列,甚至可能使用线程(我认为,池连接将是有用的),但我不能使这项工作。你能帮忙吗?

+0

嗯,如果你先使用第二个队列,它是否会颠倒顺序? –

+0

我刚刚使用继承重写了代码,现在它只是引发了一个错误“Class'sms.message.SMSMessage'未映射”。我应该投入输入对象映射类?这似乎很奇怪。 – Enchantner

我认为你的问题涉及到tablename变量。这是一个class variable,它在您创建班级时定义,并且然后不会更改。所以,对于你的两个实例,当它们通过self.tablename进行访问时,它将是相同的。要解决此问题,请将其移动到init函数中,并将其设置为self.tablename。每次创建新对象时都会初始化它。

+0

我已经更新了主题中的代码 - 在传递tablename作为构造函数参数的同时重写为使用两个队列类的继承。但它也行不通。 – Enchantner