【问题标题】:Hybrid expression that counts number rows with condition计算有条件的行数的混合表达式
【发布时间】:2014-10-23 13:26:29
【问题描述】:

我有 4 张桌子:

class Cebola(Base):
    __tablename__ = 'cebolas'
    id = Column(Integer, primary_key=True, autoincrement=True)


class Checklist(Base):
    __tablename__ = 'checklists'

    id = Column(Integer, primary_key=True, autoincrement=True)
    checklist_type = Column(String)
    cebola_id = Column(Integer, ForeignKey('cebolas.id'))
    cebola = relationship('Cebola', backref=backref('checklists'))

    __mapper_args__ = {'polymorphic_on': checklist_type,
                       'polymorphic_identity': 'generic'}


class ChecklistA(Checklist):
    __tablename__ = 'checklist_a'

    id = Column(Integer, ForeignKey('checklists.id', ondelete='CASCADE'), primary_key=True)
    notes = Column(Unicode)

    __mapper_args__ = {'polymorphic_identity': 'a'}


class ChecklistB(Checklist):
    __tablename__ = 'checklist_b'

    id = Column(Integer, ForeignKey('checklists.id', ondelete='CASCADE'), primary_key=True)
    notes = Column(Unicode)

    __mapper_args__ = {'polymorphic_identity': 'b'}

现在我需要一种方法(可能是混合属性),它可以告诉我在 notes <> '' 的 Cebola 中有多少清单。

我已添加:

class Cebola(Base):

    @hybrid_property
    def number_of_comments(self):
        return len([c for c in self.checklists if c.notes])

    @number_of_comments(cls)
    def number_of_comments(cls):
        ???

我在SQLAlchemy - Writing a hybrid method for child count 中发现了类似的问题,但我的示例稍微复杂一些。

【问题讨论】:

  • 您希望如何处理没有notes 属性的Checklist 泛型实例?
  • @van 他们可以忽略

标签: python sqlalchemy


【解决方案1】:

以下内容应该可以帮助您入门:

class Cebola(Base):
    __tablename__ = 'cebolas'
    id = Column(Integer, primary_key=True, autoincrement=True)

    @hybrid_property
    def number_of_comments(self):
        # return len([c for c in self.checklists if c.notes])
        # @NOTE:1: below will prevent error for those that do not have `notes` column
        # @NOTE:2: in any case this may issue a lot of SQL statements to load all subclasses of checklists relationship, so is not really efficient
        return len([c for c in self.checklists
                    if hasattr(c, 'notes') and c.notes])

    @number_of_comments.expression
    def number_of_comments(cls):
        from sqlalchemy import select
        ce, cl, cla, clb = [
            _.__table__ for _ in (Cebola, Checklist, ChecklistA, ChecklistB)]
        s = (
            select([func.count(cl.c.id).label("number_of_comments")])
            .select_from(cl.outerjoin(cla).outerjoin(clb))
            .where(or_(cla.c.notes != None, clb.c.notes != None))
            .where(cl.c.cebola_id == cls.id)
            .correlate(cls)
            .as_scalar()
        )
        return s

在查询中的用法:

q = session.query(Cebola, Cebola.number_of_comments)
for cebola, number_of_comments in q.all():
    print(cebola, number_of_comments)

【讨论】:

  • 感谢您的回答。我只是对混合表达式中会话的使用表示怀疑。如果还没有对象的实例,我怎么能得到它?
  • 你说得对,在混合表达式中使用session 是不正确的做法。我刚刚使用with_polymorphic 做了一个简单的查询来完成这项工作(这使所有这些LEFT OUTER JOINs 对你来说都很好)。但是您可以直接使用表达式构造相同的表达式。
  • 更新了答案,只使用没有查询实例的表达式,这将产生相同的查询。根据数据库和表的数量,您甚至可以将 where 子句移动到 join 条件的一部分,因为在某些数据库上它可能会更快。
  • 谢谢!谁会想到它是如此容易;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多