增强多态身份的 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 语法的主要内容,如果未能解决你的问题,请参考以下文章
sqlalchemy.exc.NoSuchModuleError:无法加载插件:sqlalchemy.dialects:postgres