【问题标题】:SQLAlchemy Class Decoration for __mapper_args____mapper_args__ 的 SQLAlchemy 类装饰
【发布时间】:2013-02-27 00:24:33
【问题描述】:

我有很多类是我的数据库模式多态性的一部分。 对于他们中的大多数,我(需要)这样做:

__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

【问题讨论】:

    标签: python python-2.7 sqlalchemy polymorphism


    【解决方案1】:

    使用mixin。通常它们是一场噩梦,但将公共状态注入声明性类似乎是一种合理的用途。

    class PolyMixin(object):
        __mapper_args__ = {'polymorphic_identity': 10}
    
    class SomeTable(Base, PolyMixin):
        __tablename__ = "something"
    
    class SomeOtherTable(Base, PolyMixin):
        __tablename__ = "something_else"
    

    【讨论】:

    • 我已经在使用 mixin。我的问题并不是关于他们。我不想重复 _mapper_args_ = {'polymorphic_identity': 10} 而是使用@decorator。
    • 您不必重复。只需让每个类都从 mixin 继承。装饰器可能不可靠,因为在调用装饰器时,声明魔法已经完成,映射器已经存在。
    • Eevee,再次感谢您的解释,但我认为我无法解释自己。 ;-) 我有大约 100 个类,每个类都有 mapper_args .. 行,具有不同的值。 10 只是一个例子。所有 100 个类都有 100 个不同的值,因此有 100 行 _mapper_args_ = {'polymorphic_identity': 1..100}。你是绝对正确的,装饰器不起作用,因为魔法已经发生了。所以我正在寻找一种比 100 行 _mapper_args_ = {'polymorphic_identity': 10} 更优雅的方式。你怎么看?
    • 哦,我明白了。在那种情况下,我只需将__mapper_args__ 放在每个类中:) 你有两个选择:为每个类添加一个包含数字的字典,或者找出某种疯狂的魔法,然后为每个类添加一个包含数字的装饰器班级。我认为装饰器在这里并没有真正为您节省任何东西。
    【解决方案2】:

    您的装饰器不起作用,因为它会在构建类后尝试修改它,而此时映射器已经设置好了。

    def polid(value):
        return type("mixinclass", (object,), {"__mapper_args__": {'polymorphic_identity': value}})
    
    class ClassName(polid(10), Inherited):
        pass
    

    这会在每次调用 polid 时创建一个全新的类,使用您需要的任何自定义映射器参数。

    【讨论】:

    • 有些问题足够复杂,动态类创建很有用。试图避免属性分配不是其中之一。
    【解决方案3】:

    到目前为止,可能会更好一点,不那么神奇的解决方案可能是:

    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
    

    (很遗憾)

    【讨论】:

      【解决方案4】:

      元类方法到底有什么问题?

      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,或者有一个外部字典将类名映射到值,或者甚至创建一个虚构的“基础”来记住该值以便您可以编写

      class ClassName(Inherited, Value(10)): ...
      

      事实上,我认为最后一种方法是最好的(如果您仍然坚持使用 Py2)。如果您需要帮助,请提出,我会尽力写出来。

      【讨论】:

        猜你喜欢
        • 2018-12-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-14
        • 1970-01-01
        • 2018-07-27
        • 2016-03-07
        • 2020-01-11
        相关资源
        最近更新 更多