SQLAlchemy Class Decoration for __mapper_args__

非 Y 不嫁゛ 提交于 2019-12-12 00:17:54

问题


I have a lot of classes which are part of polymorphism with my DB schema. With most of them I (need to) do:

__mapper_args__ = {'polymorphic_identity': unique_integer}
# unique_integer is a unique integer different for each class ex: 10

Instead of this, I'd like to use a decorator, ie.:

@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

How can I do this? What kind of decorator do I need to use? The following does not work (does not register):

def polid(v):
    def x(f):
        f.__mapper_args__ = {'polymorphic_identity': v}
        return f
    return x

回答1:


Use a mixin. Normally they're kind of a nightmare, but injecting common state into a declarative class seems like a reasonable use.

class PolyMixin(object):
    __mapper_args__ = {'polymorphic_identity': 10}

class SomeTable(Base, PolyMixin):
    __tablename__ = "something"

class SomeOtherTable(Base, PolyMixin):
    __tablename__ = "something_else"



回答2:


Your decorator doesn't work because it tries to modify the class after it's been constructed, and at that point the mapper has already been set up.

def polid(value):
    return type("mixinclass", (object,), {"__mapper_args__": {'polymorphic_identity': value}})

class ClassName(polid(10), Inherited):
    pass

This creates a brand new class every time polid is called, with whatever custom mapper args you require.




回答3:


Perhaps a bit better, less magical solution attained so far could be:

def PID(value):
    ''' Mixin Class Generator For Polymorphic Identity Inheritance '''
    class MixinClassForPolymorphicIdentityInheritance: 
        __mapper_args__ = {'polymorphic_identity': value}
    return MixinClassForPolymorphicIdentityInheritance

Usage:

class InheritingClass(PID(pidv), Parent): pass

(unfortunately)




回答4:


What exactly is wrong with metaclass approach?

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): ...

Of course, in Py2 you'll have to find some other way to signal information to the metaclass, but that's the price to pay for using a legacy language. :-P It shouldn't be so hard though: use a special attribute _value, or have an external dict mapping class names to values, or even make a fictional "base" remembering the value so you could write

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

In fact, I think that last approach is the best (if you're still stuck on Py2). If you need help with it, ask and I'll try to write it out.



来源:https://stackoverflow.com/questions/15102031/sqlalchemy-class-decoration-for-mapper-args

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!