我有很多类,它们是我的数据库模式的多态性的一部分。 其中大部分我都需要做:
__mapper_args__ = {'polymorphic_identity': unique_integer}
# unique_integer is a unique integer different for each class ex: 10
而不是这个,我想使用装饰器,即:
@polid(10)
class ClassName(Inherited):
# instead of repeating for each class the following:
# __mapper_args__ = {'polymorphic_identity': 10}
# I would like to have above decorator or something to do the trick.
pass
我该怎么做?我需要使用什么样的装饰器?以下不起作用(不注册):
def polid(v):
def x(f):
f.__mapper_args__ = {'polymorphic_identity': v}
return f
return x
答案 0 :(得分:2)
使用mixin。通常它们是一种噩梦,但将共同状态注入声明性类似乎是合理的用法。
class PolyMixin(object):
__mapper_args__ = {'polymorphic_identity': 10}
class SomeTable(Base, PolyMixin):
__tablename__ = "something"
class SomeOtherTable(Base, PolyMixin):
__tablename__ = "something_else"
答案 1 :(得分:1)
你的装饰器不起作用,因为它在构造之后试图修改类,并且此时已经设置了映射器。
def polid(value):
return type("mixinclass", (object,), {"__mapper_args__": {'polymorphic_identity': value}})
class ClassName(polid(10), Inherited):
pass
每次调用polid时都会创建一个全新的类,使用您需要的任何自定义映射器args。
答案 2 :(得分:1)
到目前为止,可能会更好,更不神奇的解决方案可能是:
def PID(value):
''' Mixin Class Generator For Polymorphic Identity Inheritance '''
class MixinClassForPolymorphicIdentityInheritance:
__mapper_args__ = {'polymorphic_identity': value}
return MixinClassForPolymorphicIdentityInheritance
用法:
class InheritingClass(PID(pidv), Parent): pass
(不幸的是)
答案 3 :(得分:0)
元类方法究竟出了什么问题?
class PolyMeta(DeclarativeMeta):
def __new__(cls, clsname, bases, namespace, value=None, **kwargs):
if value is not None:
namespace['__mapper_args__'] = dict(polymorphic_identity=value)
return super().__new__(cls, clsname, bases, namespace, **kwargs)
class Inherited(Base, metaclass=PolyMeta): ...
class ClassName(Inherited, value=10): ...
当然,在Py2中,您必须找到一些其他方式向元类信号发送信号,但这是使用传统语言的代价。 :-P它应该不是那么难:使用一个特殊的属性_value
,或者有一个外部dict将类名称映射到值,甚至可以创建一个虚构的“基础”来记住这个值,这样你就可以写了
class ClassName(Inherited, Value(10)): ...
事实上,我认为最后一种方法是最好的(如果你仍然坚持Py2)。如果您需要帮助,请询问,我会尝试写出来。