Python 在SQLAlchemy中创建混合属性的自定义元类
我想在SQLAlchemy之上创建一个自定义接口,以便透明地支持一些预定义的混合属性 具体地说,我想创建一个类Python 在SQLAlchemy中创建混合属性的自定义元类,python,sqlalchemy,metaclass,Python,Sqlalchemy,Metaclass,我想在SQLAlchemy之上创建一个自定义接口,以便透明地支持一些预定义的混合属性 具体地说,我想创建一个类SpecialColumn和一个元类,这样当用户添加SpecialColumn作为类的属性时,我的自定义元类会用两个SQLAlchemyColumns替换该属性,并添加一个混合属性,将这两个列作为元组获取和设置。 以下是我目前的做法: 首先,我定义了我的特殊列类型: class SpecialColumn(object): pass 然后,我定义了一个继承自Declarati
SpecialColumn
和一个元类,这样当用户添加SpecialColumn
作为类的属性时,我的自定义元类会用两个SQLAlchemyColumn
s替换该属性,并添加一个混合属性,将这两个列作为元组获取和设置。
以下是我目前的做法:
首先,我定义了我的特殊列类型:
class SpecialColumn(object):
pass
然后,我定义了一个继承自DeclarativeMeta的元类,该元类扫描类中的SpecialColumn
实例,并用两个列和一个混合属性(定义为闭包)替换它们:
最后,我用它构造了一个声明性_base
的实例,并让用户用新的基定义类:
MyBase = declarative_base(metaclass=MyDeclarativeMeta)
class MyClass(MyBase):
col1 = SpecialColumn()
col2 = Column(...)
现在回答我的问题:
首先,我的方法正确吗?
其次,如何使用元类添加setter?这样做是否正确:
def setter(self, (v1, v2)):
setattr(self, col1_name, v1)
setattr(self, col2_name, v2)
然后只需执行attrs[name].setter(setter)
?无需为SQLAlchemy映射类使用元类,因为我们提供了大量功能,可以在创建和/或映射类时向类添加功能。这里可能很好,如果您使用的是0.8,您可以直接应用到MyBase
:
@event.listens_for(MyBase, 'mapper_configured')
def get_special_columns(mapper, cls):
for attrname in dir(cls):
val = getattr(cls, attrname)
if isinstance(val, SpecialColumn):
name1, name2 = "_%s_1" % attrname, "_%s_2" % attrname
setattr(cls, name1, Column(...))
setattr(cls, name2, Column(...))
@hybrid_property
def myhybrid(self):
return getattr(self, name1), getattr(self, name2)
@myhybrid.setter
def myhybrid(self, value):
setattr(self, name1, value[0])
setattr(self, name2, value[1])
setattr(cls, attrname, myhybrid)
请注意,setattr()是最好的方法,简单明了,切中要害。感谢您的回复和SQLAlchemy!
@event.listens_for(MyBase, 'mapper_configured')
def get_special_columns(mapper, cls):
for attrname in dir(cls):
val = getattr(cls, attrname)
if isinstance(val, SpecialColumn):
name1, name2 = "_%s_1" % attrname, "_%s_2" % attrname
setattr(cls, name1, Column(...))
setattr(cls, name2, Column(...))
@hybrid_property
def myhybrid(self):
return getattr(self, name1), getattr(self, name2)
@myhybrid.setter
def myhybrid(self, value):
setattr(self, name1, value[0])
setattr(self, name2, value[1])
setattr(cls, attrname, myhybrid)