2016-07-21 6 views
12

Python 3.5 ve SQLAlchemy 1.0.14 (ORM) öğelerini kullanma.SQLAlchemy ORM: Polimorfik Tek Tablo Kalıtımı, "polimorfik_kimliği" bulunmazsa üst sınıfa geri dönüş ile birlikte

from sqlalchemy.ext.declarative.api import declarative_base 

Base = declarative_base() 

class Item(Base): 
    __tablename__ = 'items' 

    id = Column(Integer, primary_key=True) 
    type = Column(String) 
    # other non relevant attributes 

Öğelerim pek çok farklı türde olabilir tip belirleyicisi type saklanmasını:

Böyle olarak ilan öğelerin bir tablo var. Bu nesne türlerinden bazıları için, belirli yöntemlere veya özniteliklere sahip olmam gerekiyor. yüklenecek tüm ihtisas öğeleri (type=='specialitem' sahip) ister ki, benim öğeleri yüklediğinizde Şimdi

class Item(Base): 
    __tablename__ = 'items' 

    id = Column(Integer, primary_key=True) 
    type = Column(String, index=True) 
    # other non relevant attributes 

    __mapper_args__ = { 
     'polymorphic_on': type, 
    } 

class SpecialisedItem(Base): 
    __mapper_args__ = { 
     'polymorphic_identity': 'specialitem', 
    } 

    def specialised_method(self): 
     return "I am special" 

:

Ben Öğesi'nin alt sınıf gibi çeşitli SpecialisedItem ile tek tablo devralma kullanmaya çalıştı Bunu başarmak için bu şekilde, başka bir tip değeri, yüklenmekte olan üst sınıf Item ile sonuçlanır. Bu işe yaramazsa, öğeleri yüklerken AssertionError: No such polymorphic_identity 'normal' is defined alırım.

yerine üst sınıf Item geri düşen type "bağlanılmayan" sahip sadece olası tüm type değerleri kapsayacak şekilde hiçbir şey miras sınıfları oluşturmaktan kaçınmak istiyorum.

Bu sonuca ulaşmak için herhangi bir yolu var mı? referans için

En az bir test durumu:

from sqlalchemy.engine import create_engine 
from sqlalchemy.ext.declarative.api import declarative_base 
from sqlalchemy.orm.session import sessionmaker 
from sqlalchemy.sql.schema import Column 
from sqlalchemy.sql.sqltypes import Integer, String 


Base = declarative_base() 

class Item(Base): 
    __tablename__ = 'items' 

    id = Column(Integer, primary_key=True) 
    type = Column(String, index=True) 
    # other non relevant attributes 

    __mapper_args__ = { 
     'polymorphic_on': type, 
    } 

class SpecialisedItem(Item): 
    __mapper_args__ = { 
     'polymorphic_identity': 'special', 
    } 

    specialAttribute = Column(String) 

    def specialised_method(self): 
     return "I am special" 


engine = create_engine("sqlite:///:memory:") 
Base.metadata.create_all(engine) 
Session = sessionmaker(bind=engine) 
session = Session() 

session.add(Item(type='normal')) 
session.add(Item(type='special')) 
session.commit() 
# loading only specialized items works 
for item in session.query(Item).filter_by(type="special"): 
    print(item.specialised_method()) 

# loading other items fails 
for item in session.query(Item): 
    print(item.type) 

sayesinde

Guillaume

cevap

6

örnekleri Eşleyici'ye “polimorfık özdeşlik” tanımlayıcılarının bir eşleme polymorphic_map dict depolanır. Tanımlanmamış polimorfik kimlikler için üst sınıf eşleştiricisini döndürecek özel polymorphic_map oluşturabilirsiniz.

from sqlalchemy.engine import create_engine 
from sqlalchemy.ext.declarative.api import declarative_base 
from sqlalchemy.orm.session import sessionmaker 
from sqlalchemy.sql.schema import Column 
from sqlalchemy.sql.sqltypes import Integer, String 
from sqlalchemy import event 

Base = declarative_base() 

class Item(Base): 
    __tablename__ = 'items' 

    id = Column(Integer, primary_key=True) 
    type = Column(String, index=True) 
    # other non relevant attributes 

    __mapper_args__ = { 
     'polymorphic_on': type, 
    } 

class SpecialisedItem(Item): 
    __mapper_args__ = { 
     'polymorphic_identity': 'special', 
    } 

    specialAttribute = Column(String) 

    def specialised_method(self): 
     return "I am special" 

#http://docs.sqlalchemy.org/en/rel_1_1/orm/events.html#sqlalchemy.orm.events.MapperEvents.mapper_configured 
@event.listens_for(Item, 'mapper_configured') 
def receive_mapper_configured(mapper, class_): 
    class FallbackToParentPolymorphicMap(dict): 
     def __missing__(self, key): 
      # return parent Item's mapper for undefined polymorphic_identity 
      return mapper 

    new_polymorphic_map = FallbackToParentPolymorphicMap() 
    new_polymorphic_map.update(mapper.polymorphic_map) 
    mapper.polymorphic_map = new_polymorphic_map 

    # for prevent 'incompatible polymorphic identity' warning, not necessarily 
    mapper._validate_polymorphic_identity = None 

engine = create_engine("sqlite:///:memory:") 
Base.metadata.create_all(engine) 
Session = sessionmaker(bind=engine) 
session = Session() 

session.add(Item(type='normal')) 
session.add(Item(type='special')) 
session.commit() 
# loading only specialized items works 
for item in session.query(Item).filter_by(type="special"): 
    print(item.specialised_method()) 

# loading other items fails 
for item in session.query(Item): 
    print(item.type) 
+0

Bu işe yarıyor, teşekkürler! Eğer sakıncası yoksa, yanıt kodunuzu doğrudan çalışarak güncelledim. Ödül kazanacaksın. – Guillaume