增强SQLAlchemy语法以实现多态身份

Deb*_*ski 5 python sqlalchemy metaclass

我有一个声明性基类Entity,它将列定义name为多态,例如

class Entity(DeclarativeBase):
    name = Column('name', String(40))
    __mapper_args__ = {'polymorphic_on':name}
Run Code Online (Sandbox Code Playgroud)

在子类中,我现在可以说

class Experiment(Entity):
    __mapper_args__ = {'polymorphic_identity': "experiment"}
Run Code Online (Sandbox Code Playgroud)

并完成.但是,我想为我的库用户简化子类的创建,因此可以实现以下目标:

  • 有一个更好的语法,它不像默认语法那样复杂.这可能是类中的简单赋值poly_id = "exp",也可能是类装饰器.
  • 如果没有给出polymorphic_identity,则从子类的名称中提取名称.

我尝试使用元类(仅第二部分)完成此操作:

from sqlalchemy.ext.declarative import DeclarativeMeta

class Meta(type):
    def __init__(cls, classname, bases, dict_):
        dict_["__mapper_args__"] = {'polymorphic_identity': classname}
        return super(Meta, cls).__init__(classname, bases, dict_)

class CombinedMeta(Meta, DeclarativeMeta):
    pass

class Experiment(Entity):
    __metaclass__ = CombinedMeta
Run Code Online (Sandbox Code Playgroud)

所以,在我看来,我Meta应该在调用之前设置名称,DeclarativeMeta但它似乎不起作用.因此,DeclarativeMeta无论如何设置多态名称都不会看到更改,因为我弄乱了MRO或者我正在做的事情无论如何都是完全错误的.我需要改变什么,或者SQLAlchemy中是否还有这样的东西?

Deb*_*ski 7

对我感到羞耻,但问题很容易通过不使用dict_但通过直接设置属性来解决cls.

class Meta(DeclarativeMeta):
    def __init__(cls, *args, **kw):
        if getattr(cls, '_decl_class_registry', None) is None:
            return # they use this in the docs, so maybe its not a bad idea
        cls.__mapper_args__ = {'polymorphic_identity': cls.__name__}
        return super(Meta, cls).__init__(*args, **kw)

class Experiment(Entity):
    __metaclass__ = Meta
Run Code Online (Sandbox Code Playgroud)