Reputation: 14671
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
Upvotes: 0
Views: 3590
Reputation: 2755
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.
Upvotes: 0
Reputation: 14671
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)
Upvotes: 1
Reputation: 1186
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.
Upvotes: 1
Reputation: 48564
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"
Upvotes: 2