2010-12-16 16 views
5

name sütununu polimorfik olarak tanımlayan Entity numaralı bir bildirim sınıfım var.Polimorfik kimlik için SQLAlchemy sözdizimini geliştirin

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

alt sınıfları, ben şimdi

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

söyleyebiliriz ve yapılması gereken. Ancak, benim kütüphanenin kullanıcıları için alt sınıflarının oluşturulmasını kolaylaştırmak ve bu nedenle yapmak istiyorum mümkün şunlardır:

  • varsayılan sözdizimi kadar dolambaçlı değil onun için daha iyi sözdizimi var. Bu, sınıfın içinde veya belki de bir sınıf dekoratöründe poly_id = "exp"'un basit bir ataması olabilir.
  • Polimorfik bir kimlik belirtilmezse, adı alt sınıfın adından çıkarın.

ben bu işi metaclasses kullanarak (sadece ikinci bölümünü) almaya çalıştı: böylece

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 

, bence, benim MetaDeclarativeMeta çağırmadan önce adını ayarlamak gerekir ama o görünmüyor çalışmak. Yani ya polimorfik ismi belirlediği varsayılan DeclarativeMeta, MRO'yu karıştırdığımdan ya da yaptığım şey zaten yanlış bir yanlıştır. SQLAlchemy'de neye benzer bir değişiklik yapmam gerekiyordu ya da böyle bir şey var mı?

+0

'__init__' çağrıldığında, sınıf zaten oluşturulmuştur. __init__' bir kurucu değil. Eğer bunu __new__' içinde yaptıysanız, sorunsuz çalışırdı. Ve pek çok meta sınıfına sahip olmanıza gerek yok ... sadece sınıf MyMeta (DeclarativeMeta): ... 've sonra bildirimsel tablonuzu MyMeta'dan başlat. – Veky

cevap

7

Utanç (Ben sadece sürümleri> = 0.6 çalışıp çalışmadığından emin değilim ya sadece daha iyi şimdi belgelenmiş ise) bu tür amaçlar için mixin sınıfları kullanmanın yollarını göstermek Benim üzerimde sorun ancak dict_ kullanarak değil özniteliği doğrudan cls olarak ayarlayarak çözülebilir.

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