我有一个类是SQLAlchemy的声明基础的后代。我需要编写一个桥接对象,它将在声明性基础和我正在运行的另一个系统之间进行转换,但我希望桥接对象不必确切知道记录中的列。在这种情况下,我想要一种方法来列出记录中的所有列,以避免在两个只是模糊相关的位置维护属性列表,并在此期间最小化复制。这意味着我可以创建列属性,然后维护一个单独的列名列表,但同样,复制是一个因素 - 如果我想稍后改变这个东西的结构,我必须在两个地方改变它。
在这种情况下,我考虑将列定义粘贴在dict中,然后遍历dict以使用setattr创建每个列定义,如下所示:
for k,v in self.__column_dict.items():
setattr(self,k,
sqlalchemy.Column(v['column_type'],**v.get('opts',{})),
)
现在,这就是问题:如果我在类级别上粘贴这些代码,那么self还没有定义,我得到一个错误(这是有道理的)。如果我在__init__
中坚持这一点,则自定义,但是SQLAlchemy的声明性基础会产生错误,因为在类完成定义时表上没有主键(这是有意义的,因为这些属性赢了' t设置到运行时间。)
所以,这就是说,如何在不使用eval的情况下得到我想要的东西,或者在这里使用eval我唯一的选择?
class MyMeta(DeclarativeMeta):
def __new__(meta, classname, bases, dict_):
klass = type.__new__(meta, classname, bases, dict_)
if dict_.has_key('__classinit__'):
klass.__classinit__ = staticmethod(klass.__classinit__.im_func)
klass.__classinit__(klass, dict_)
return klass
然后,在我的派生类中,
class DerivedClass(declarative_base()):
__tablename__ = 'yaddayadda'
__metaclass__ = MyMeta
def __classinit__(klass, dict_):
klass.__column_dict = <column dict here>
for k,v in klass.__column_dict.items():
setattr(klass,k,
<fancy column stuff>
)
...<rest of class definition>...
答案 0 :(得分:1)
这可以通过向declarative_base提供元类来完成 并在那个元类
from sqlalchemy import Column, Integer
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
class MyMeta(DeclarativeMeta):
def __init__(klass, classname, bases, dict_):
for k, v in dict_.items():
if k.endswith('__column_dict'):
for name, datatype, is_pk in v:
setattr(klass, name, Column(name, datatype, primary_key=is_pk))
return DeclarativeMeta.__init__(klass, classname, bases, dict_)
Base = declarative_base(metaclass=MyMeta)
class Bob(Base):
__tablename__ = 'bob'
__column_dict = [('a', Integer, True), ('b', Integer, False)]
bob = Bob()
print bob.a
print bob.b