2016-04-06 12 views
1

Sorunun başlığı kafa karıştırıcı olabilir, ancak aşağıdaki sorunu açıkladığımı düşünüyorum.Bir SQLAlchemy modeli parametresine en uygun erişim n Uzak bağlantı sayısı

SQLAlchemy ile oluşturduğum çeşitli bildirimsel "test türü" modellerim var. Her "test tipi" modeli, "konum" üzerinde yer alan bir "ekipman" parçası ile ilişkilidir. Bu nedenle, her bir test türünün, gerçek test modelinden uzak bir şekilde değişen sayıda ilişki içerdiği bir "location.name" parametresi vardır. Her "test" nesnesine ilişkilendirilecek bu "location.name" değerine ihtiyacım var.

Kurduğum şekilde, testleri sorgularken bir ton SQL yükler. Bunun ilişki kaskatı yüzünden olduğunu hayal ediyorum. Tüm testleri tek bir tabloda görüntülerim ve testlerin bir şekilde ilişkilendirildikleri yere göre filtreleyebilmelerini isterim.

Bu model yapılandırması benim için yeni ve ham SQL ile nasıl etkileşimde bulunacağımı bilmiyorum, yalnızca modellerle nasıl çalışacağımı biliyorum.

Belirli bir test örneğinin konum adı parametresini almanın en iyi yolunun ne olduğunu merak ediyorum. Her testin get_json() işlevinde location.name döndüğüne dikkat etmeme rağmen, daha az SQL yayan ve tüm test türlerini filtrelemeye geldiğinde simpeler olacak daha iyi bir yol olduğunu umuyorum.

Umarım aşağıda modeli tanımları bu açık

class Location(Model): 
    __tablename__ = 'locations' 
    id = Column(Integer, Sequence('location_id_seq'), primary_key=True) 
    name = Column(String(50), unique=True) 
    ... 


class EquipmentFoo(Model): 
    __tablename__ = 'equipmentfoos' 
    id = Column(Integer, Sequence('equipmentfoo_id_seq'), primary_key=True) 
    location_id = Column(Integer, ForeignKey('locations.id')) 
    location = relationship('Location', backref='equipmentfoos') 
    footests = relationship('FooTest', backref='equipmentfoo') 
    ... 


class EquipmentBar(Model): 
    __tablename__ = 'equipmentbars' 
    id = Column(Integer, Sequence('equipmentbar_id_seq'), primary_key=True) 
    equipmentfoo_id = Column(Integer, ForeignKey('equipmentfoos.id')) 
    equipmentfoo = relationship('EquipmentFoo', backref='equipmentbars') 
    bartests = relationship('BarTest', backref='equipmentbar') 
    ... 


class EquipmentZab(Model): 
    __tablename__ = 'equipmentzabs' 
    id = Column(Integer, Sequence('equipmentzab_id_seq'), primary_key=True) 
    equipmentbar_id = Column(Integer, ForeignKey('equipmentbars.id')) 
    equipmentbar = relationship('EquipmentBar', backref='equipmentzabs') 
    zabtests = relationship('ZabTest', backref='equipmentzab') 
    ... 

Yani ekipman modelleri vardır yapmak ve nasıl bir konuma ilgilidir. Ayrıca aşağıdaki kendi testlerine göre ilişkileri de dahildir.

class HasId(object): 
    @declared_attr 
    def id(cls): 
     return Column('id', Integer, Sequence('test_id_seq'), primary_key=True) 
    @declared_attr 
    def status(cls): 
     return Column('status', String(50)) 
    ... 


class TestParent(HasId, Model): 
    __tablename__ = 'tests' 
    discriminator = Column(String(50)) 
    __mapper_args__ = {'polymorphic_on': discriminator} 
    ... 
    def parent_json(self): 
     return {'id': self.id, 
       'status': self.status, 
       ... 
       }   


class FooTest(TestParent): 
    __tablename__ = 'footests' 
    __mapper_args__ = {'polymorphic_identity': 'footests'} 
    id = Column(Integer, ForeignKey('tests.id'), primary_key=True) cascade='save-update, merge') 
    pressure_start = Column(Float) 
    ... 
    def get_json(): 
     my_json = {'location': self.equipmentfoo.location.name, 
        'pressure_start': self.pressure_start, 
        ... 
        } 
     parent_json = super(FooTest, self).parent_json() 
     my_json.update(parent_json) 
     return my_json 


class BarTest(TestParent): 
    __tablename__ = 'bartests' 
    __mapper_args__ = {'polymorphic_identity': 'bartests'} 
    id = Column(Integer, ForeignKey('tests.id'), primary_key=True) cascade='save-update, merge') 
    hatch_value = Column(Boolean) 
    ... 
    def get_json(): 
     my_json = {'location': self.equipmentbar.equipmentfoo.location.name, 
        'hatch_value': self.hatch_value, 
        ... 
        } 
     parent_json = super(BarTest, self).parent_json() 
     my_json.update(parent_json) 
     return my_json 


class ZabTest(TestParent): 
    __tablename__ = 'zabtests' 
    __mapper_args__ = {'polymorphic_identity': 'zabtests'} 
    id = Column(Integer, ForeignKey('tests.id'), primary_key=True) cascade='save-update, merge') 
    safety_check = Column(Boolean) 
    ... 
    def get_json(): 
     my_json = {'location': self.equipmentzab.equipmentbar.equipmentfoo.location.name, 
        'safety_check': self.hatch_value, 
        ... 
        } 
     parent_json = super(ZabTest, self).parent_json() 
     my_json.update(parent_json) 
     return my_json 

cevap

1

Varsayılan olarak, ilişkiler yüklenmez. Bu, bir veri kaynağına ilk kez eriştiğinizde, veriyi almak için bir sorgu gönderilir ve bu da 'un ilişkisini yüklemez. Senaryo için, nZabTest örneklerinde, konumun adını almak için 4n sorguları yayar.

Birçok küçük işlemin verimli hale getirilmesine yönelik genel yaklaşım, bir çok işlemin yükünü bir araya getiren bir işlemdir. Bunu SQL'de yapmanın yolu, her seferinde bir satır yerine aynı anda birden çok satır sorgulamaktır.

session.query(ZabTest).options(
    joinedload(ZabTest.equipmentzab) 
    .joinedload(EquipmentZab.equipmentbar) 
    .joinedload(EquipmentBar.equipmentfoo) 
    .joinedload(EquipmentFoo.location)) 

Ne gerçekleştirir tek sorguda kendini, ZabTest dahil self.equipmentbar.equipmentfoo.location.name tüm zincirini doldurur geçerli: SQLAlchemy eager loading aracılığıyla bu yeteneğini ortaya çıkarır.

Alternatif olarak, hep istekli yüke SQLAlchemy yapılandırabilirsiniz:

zabtests = relationship('ZabTest', backref=backref('equipmentzab', lazy="joined")) 

Forewarned: Ayrıca devralma kullanırken beri hevesli yükleme sözdizimi kıllı alabilirsiniz. Her zaman doğru bir şekilde katıldığınızdan emin olmak için yayılan SQL'i kontrol edin.

+0

Bazen filtrelemek için açıkça katılmanız gerekir. Eğer durum buysa, 'include_eager' kullanmalısınız, aksi halde sqlalchemy aynı zamanda ilişkiler için anonim birleştirme yapacak. –