问题的标题可能令人困惑,但我相信我已经在下面描述了这个问题。
我有各种声明"测试类型"我用SQLAlchemy构建的模型。每个"测试类型"模型与一个"设备"位于"位置"。因此,每个测试类型都有一个" location.name"参数与实际测试模型之间存在不同数量的关系。我需要这个" location.name"与每个"测试"相关联的值宾语。
我设置它的方式现在在查询测试时会发出大量的SQL。我想这是因为关系级联。我在一个表中显示所有测试,我希望能够以某种方式根据它们所关联的位置过滤测试。
这个模型配置对我来说是新的,我不知道如何使用原始SQL
与它进行交互,我只知道如何使用模型。
我想知道获取特定测试实例的位置名称参数的最佳方法是什么。请注意,每个测试的location.name
函数都会返回get_json()
,尽管我希望有一种更好的方法可以减少SQL并且在过滤所有测试类型时更加简单。
希望以下模型定义明确
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')
...
因此,有设备模型以及它们与位置的关系。还包括他们与下面各自测试的关系。
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
答案 0 :(得分:1)
默认情况下,不会加载关系。这意味着当您第一次访问关系时,会发出查询以获取数据,而数据又不会加载其关系。对于您的方案,对于n
ZabTest
个实例,它会发出4n
个查询以获取该位置的名称。
使许多小型操作高效的一般方法是通过批处理,将许多操作的开销合二为一。在SQL中执行此操作的方法是一次查询多行而不是一次查询一行。 SQLAlchemy通过eager loading公开此功能:
session.query(ZabTest).options(
joinedload(ZabTest.equipmentzab)
.joinedload(EquipmentZab.equipmentbar)
.joinedload(EquipmentBar.equipmentfoo)
.joinedload(EquipmentFoo.location))
这实现了它在一个查询中填充了self.equipmentbar.equipmentfoo.location.name
的整个链,包括ZabTest
本身,。
或者,您可以将SQLAlchemy配置为始终预先加载:
zabtests = relationship('ZabTest', backref=backref('equipmentzab', lazy="joined"))
预先警告:因为你也在使用继承,所以急切的加载语法可能会变得毛茸茸。始终检查发出的SQL以确保正确连接。