增强SQLAlchemy多态标识的语法
我有一个声明式的基类 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"
,或者使用类装饰器。 - 如果没有给出多态身份,就从子类的名字中提取名称。
我尝试用元类来实现这个(只实现第二部分):
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 中已经有类似的东西吗?
2 个回答
1
最近的sqlalchemy文档展示了如何使用混合类来实现这些功能(我不确定这是否只在版本>= 0.6中有效,还是现在只是文档写得更清楚了)
http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative/mixins.html
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