我有一个类是 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__
, self 被定义,但 SQLAlchemy 的声明性基础给出了一个错误,因为在类完成定义时表上没有主键(这是有道理的,因为这些属性直到运行时才会设置)。
所以,说了这么多,我如何在不使用 eval 的情况下获得我想要的东西,或者在这里使用 eval 是我唯一的选择?
编辑:我接受了下面的解决方案,但没有 100% 使用它(尽管它绝对有助于让我得到答案)。这是我最终做的事情:(请注意,DeclarativeMeta 是 sqlalchemy.ext.declarative 的一部分,与 declarative_base 相同的包)
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>...