python - sqlalchemy 与 `len(query.all())` 和 `query.count()` 不同的值

标签 python count sqlalchemy polymorphism

这是一个示例代码。

一个文档有很多条评论

PostComment extends Comment(具有 sqlalchemy 多态特性)

某些查询在 len(query.all())query.count() 之间返回不同的结果

  • sqlalchemy 版本:1.0.8
  • mysql版本:5.6.25

请参阅下面的主要功能。

发生了什么事?

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Table, Column, Integer, Float, Boolean, ForeignKey, String, Unicode, DateTime, Date, UniqueConstraint
from sqlalchemy.orm import relationship, backref

engine = create_engine('mysql://root:root@192.168.59.103:3306/document')

DBSession = scoped_session(sessionmaker(bind=engine))

Base = declarative_base()
Base.metadata.bind = engine

class Document(Base):
    __tablename__ = 'document'

    id = Column(Integer, primary_key=True)


class Comment(Base):
    __tablename__ = 'comment'

    id = Column(Integer, primary_key=True)
    type = Column(String(50))
    document_id = Column(Integer, ForeignKey('document.id'), primary_key=True)
    document = relationship('Document', backref=backref('comments', lazy='dynamic'))

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


class PostComment(Comment):
    __tablename__ = 'post_comment'

    id = Column(Integer, ForeignKey('comment.id'), primary_key=True)
    ready = Column(Boolean)

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



def main():
    Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)

    d1 = Document()
    DBSession.add(d1)

    d2 = Document()
    DBSession.add(d2)

    c1 = PostComment(document=d1, ready=True)
    DBSession.add(c1)

    c2 = PostComment(document=d1, ready=True)
    DBSession.add(c2)

    c3 = PostComment(document=d2, ready=True)
    DBSession.add(c3)

    c4 = PostComment(document=d2, ready=True)
    DBSession.add(c4)

    DBSession.commit()

    query = d1.comments.filter(PostComment.ready==True)

    print len(query.all())      # returns 2
    print query.count()         # returns 8


if __name__ == '__main__':
    main()

更新

http://docs.sqlalchemy.org/en/rel_1_0/orm/query.html#sqlalchemy.orm.query.Query.count

它说“返回此查询将返回的行数。”。

最佳答案

为什么结果是 8 而不是 2?因为您得到的查询是笛卡尔积 (8 = 2 * 2 * 2)。
反过来,发生这种情况是因为您有动态关系继承,它从两个表创建select(commentpost_comment) 之间没有任何谓词。

为什么第一个查询只返回 2?好吧,因为您要求的是实际的映射实例,所以 sqlalchemy 足够聪明,可以过滤掉重复项,尽管底层 SQL 语句也返回 8 行。

在您的查询中添加一个join 来解决这个问题:

query = d1.comments.join(PostComment).filter(PostComment.ready == True)

关于python - sqlalchemy 与 `len(query.all())` 和 `query.count()` 不同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32435346/

相关文章:

postgresql - 无法使用 docker compose 通过 postgresql 启动 FastAPI 服务器

python - 正则表达式 : Preceding token is not quantifiable

python - 获取正则表达式匹配后的第一个单词

python - 如何使用 subprocess.POPEN 获取异步输入和输出

r - 计算每行唯一值的数量

python - 如何将多个 "x AND y"条件与 WHERE 子句的 OR 结合起来

python - 如何从 Ableton Live 控制表面脚本将 MIDI 数据发送到我的 Arduino 板

mysql - 计算同一查询中不同表的行数

sql - 查询滚动日期范围内不同值的计数

python - 反射(reflect)所有不属于用户但已授予同义词的表