2010-12-16 63 views
5

我有一個聲明性基類Entity,它將列name定義爲多態,例如,爲多態標識增強SQLAlchemy語法

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中有這樣的東西?

+0

當'__init__'被調用時,類已經被構造。 '__init__'不是構造函數。如果你是在'__new__'中做到這一點的話,它可以毫無問題地工作。而且你不必有那麼多的元類......只是'MyMeta(DeclarativeMeta):...'類,然後從MyMeta中實例化你的聲明基。 – Veky 2015-07-16 10:37:16

回答

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 
1

最近SQLAlchemy的文檔顯示了使用混入類用於此目的的方式(我不知道是否只能在版本> = 0.6,或者如果它只是現在好多了記錄)

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

+0

這實際上並不適用於這種形式,因爲它不允許我動態設置'__mapper_args__';它只允許我在所有使用mixin的類中設置一個預定義的__mapper_args__。 – Debilski 2010-12-16 15:52:30