增强多态身份的 SQLAlchemy 语法

Posted

技术标签:

【中文标题】增强多态身份的 SQLAlchemy 语法【英文标题】:Enhance SQLAlchemy syntax for polymorphic identity 【发布时间】:2011-05-26 12:57:21 【问题描述】:

我有一个声明性基类 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 中是否已经有类似的东西?

【问题讨论】:

__init__被调用时,这个类已经被构造好了。 __init__ 不是构造函数。如果您在__new__ 中执行此操作,它将毫无问题地工作。而且您不必拥有这么多元类...只需 class MyMeta(DeclarativeMeta): ... 然后从 MyMeta 实例化您的声明性基础。 【参考方案1】:

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

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

【讨论】:

这在那种形式下实际上不起作用,因为它不允许我动态设置__mapper_args__;它只允许我在使用 mixin 的所有类中设置一个预定义的__mapper_args__【参考方案2】:

真可惜,但问题可以通过不使用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

【讨论】:

以上是关于增强多态身份的 SQLAlchemy 语法的主要内容,如果未能解决你的问题,请参考以下文章

flask mysql sqlalchemy教程

Python 学习笔记 - SQLAlchemy(下)

sqlalchemy.exc.NoSuchModuleError:无法加载插件:sqlalchemy.dialects:postgres

“SQLAlchemy”类中未解析的属性“Column”

Python 学习笔记 - sqlAlchemy(初稿)

使用flask-sqlalchemy连接mysql遇到的问题