5

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

class Entity(DeclarativeBase):
    name = Column('name', String(40))
    __mapper_args__ = {'polymorphic_on':name}

在子类中,我现在可以说

class Experiment(Entity):
    __mapper_args__ = {'polymorphic_identity': "experiment"}

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

  • 有一个更好的语法,它不像默认语法那样复杂。这可能是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

因此,在我看来,我Meta应该在调用之前设置名称,DeclarativeMeta但它似乎不起作用。因此,DeclarativeMeta由于我搞砸了 MRO 或者我正在做的事情是完全错误的,所以应该设置多态名称的那个永远不会看到变化。我需要改变什么,或者在 SQLAlchemy 中已经有类似的东西了吗?

4

2 回答 2

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
于 2010-12-16T16:09:05.070 回答
1

最近的 sqlalchemy 文档展示了为此目的使用 mixin 类的方法(我不确定它是否仅适用于 >= 0.6 的版本,或者现在是否有更好的文档记录)

http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative/mixins.html

于 2010-12-16T15:25:08.147 回答