在SQLAlchemy ORM中,如何获取session.query().group_by()中使用的主键列?

2024-05-29 03:54:28 发布

您现在位置:Python中文网/ 问答频道 /正文

问题:

如何获得多态层次结构中模型类及其所有父类的所有主键列的列表,以便在session.query().group_by中使用它

细节

在SQLAlchemy ORM中,如果我查询的类是多态层次结构的一部分,并且我想GROUP BY它的主键,那么我还必须GROUP BY多态层次结构中它的父级的所有主键

想象一下受sqlalchemy文档的Mapping Class Inheritance Hierarchies部分启发的以下设置:

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    type = Column(String(50))

    __mapper_args__ = {
        'polymorphic_identity':'employee',
        'polymorphic_on':type
    }

class Engineer(Employee):
    __tablename__ = 'engineer'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    engineer_name = Column(String(30))

    __mapper_args__ = {
        'polymorphic_identity':'engineer',
    }

class EngineeringTask(Base):
    __tablename__ = 'engineering_task'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))

    assigned_engineer_id = Column(ForeignKey(Engineer.id))
    assigned_engineer = relationship(Engineer, backref=backref("assigned_tasks", lazy="dynamic"))

如果我想做这样的查询

session.query(
    Engineer,
).join(
    Engineer.assigned_tasks,
).add_columns(
    func.count(EngineeringTask.id).label('assigned_task_count'),
).group_by(Engineer.id, Employee.id)

这种查询可以在PostgreSQLbecause(emphasis mine)中进行,它从EngineerEmployee中选择所有列,但不聚合它们:

When GROUP BY is present (...) it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions or when the ungrouped column is functionally dependent on the grouped columns, since there would otherwise be more than one possible value to return for an ungrouped column. A functional dependency exists if the grouped columns (or a subset thereof) are the primary key of the table containing the ungrouped column.

但它要求我知道/关心/记住我正在选择的映射类的所有主键列以及多态层次结构中的所有父类(Engineer.idEmployee.id

如何动态获取多态层次结构中Engineer的所有主键列和所有父级的列表


Tags: columnsthekeyidstring层次结构employeecolumn
1条回答
网友
1楼 · 发布于 2024-05-29 03:54:28

到目前为止,我能想到的最好的功能是:

from sqlalchemy import inspect

def polymorphic_primary_keys(cls): 
    mapper = inspect(cls)
    yield from (column for column in mapper.columns if column.primary_key) 
    if mapper.inherits is not None: 
        yield from polymorphic_primary_keys(mapper.inherits.entity)

像这样使用它:

query = session.query(
    Engineer,
).join(
    Engineer.assigned_tasks,
).add_columns(
    func.count(EngineeringTask.id).label('assigned_task_count'),
).group_by(*polymorphic_primary_keys(Engineer))

其中inspect(Engineer)返回Engineer.__mapper__,它是包含以下内容的^{}

  • ^{},映射模型列的迭代器/字典/属性访问器
  • ^{},它是父实体的映射程序(如果有)

由于以下几个原因,这并不令人满意:

  • ^{}应该是主键上的迭代器,但我不能使用它,因为它返回最顶层父级的主键,而不是当前映射的实体,所以我必须在Mapper.columns上迭代并检查primary_key属性

  • 有一个^{}方法和一个^{}属性,它们都返回一个迭代器,其中包含当前映射器和当前实体的所有“下游”子类的映射器。为什么没有一个等价的超类

但是它完成了任务

相关问题 更多 >

    热门问题