说我有以下型号:
class Department(Base):
__tablename__ = 'departments'
id = Column(Integer, primary_key=True)
class Employee(Base):
__tablename__ = 'employees'
id = Column(Integer, primary_key=True)
department_id = Column(None, ForeignKey(Department.id), nullable=False)
department = relationship(Department, backref=backref('employees'))
有时,当我查询部门时,我还想获取他们拥有的员工数量。我可以使用column_property
实现此目的,如下所示:
Department.employee_count = column_property(
select([func.count(Employee.id)])
.where(Employee.department_id == Department.id)
.correlate_except(Employee))
Department.query.get(1).employee_count # Works
但是,即使我不需要,也可以通过子查询获取总是。显然,我不能要求SQLAlchemy在查询时不加载它:
Department.query.options(noload(Department.employee_count)).all()
# Exception: can't locate strategy for <class 'sqlalchemy.orm.properties.ColumnProperty'> (('lazy', 'noload'),)
我也尝试使用混合属性而不是列属性来实现它:
class Department(Base):
#...
@hybrid_property
def employee_count(self):
return len(self.employees)
@employee_count.expression
def employee_count(cls):
return (
select([func.count(Employee.id)])
.where(Employee.department_id == cls.id)
.correlate_except(Employee))
没有运气:
Department.query.options(joinedload('employee_count')).all()
# AttributeError: 'Select' object has no attribute 'property'
我知道我可以在查询中查询计数作为一个单独的实体,但我真的更喜欢将它作为模型的属性。这在SQLAlchemy中甚至可能吗?
编辑:为了澄清,我想避免N + 1问题并让员工数量在与部门相同的查询中加载,而不是在每个部门的单独查询中。
答案 0 :(得分:3)
您尝试的加载策略适用于关系。加载column_property
的方式与普通列的方式相同,请参阅Deferred Column Loading。
默认情况下,您可以将employee_count
传递给deferred=True
,以延迟加载column_property
。延迟列时,访问属性时会发出select语句。
defer
的 undefer
和sqlalchemy.orm
允许在构建查询时更改此内容:
from sqlalchemy.orm import undefer
Department.query.options(undefer('employee_count')).all()