Python sqlalchemy的值与'len(query.all())'和'query.count()不同`

Python sqlalchemy的值与'len(query.all())'和'query.count()不同`,python,count,sqlalchemy,polymorphism,Python,Count,Sqlalchemy,Polymorphism,这是一个示例代码 文档有许多注释 PostComment扩展注释(使用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.

这是一个示例代码

文档有许多注释

PostComment扩展注释(使用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()
更新


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

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

为什么第一个查询只返回
2
?因为您需要实际的映射实例,
sqlalchemy
非常聪明,可以过滤掉重复的实例,尽管底层的
SQL
语句也返回8行

向查询中添加一个
join
,以解决此问题:

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

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

为什么第一个查询只返回
2
?因为您需要实际的映射实例,
sqlalchemy
非常聪明,可以过滤掉重复的实例,尽管底层的
SQL
语句也返回8行

向查询中添加一个
join
,以解决此问题:

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

我正在使用旁路查询
query=d1.comments.filter(PostComment.ready==True,PostComment.id==Comment.id)
但这不是我想要的。我使用的是旁路查询
query=d1.comments.filter(PostComment.ready==True,PostComment.id==Comment.id)
但这不是我想要的。它表示“返回此查询将返回的行数”。这在语义上不是错了吗?不是。该查询实际上返回8行。但只有当查询结果转换为映射对象列表时,这才减少到2。真正的问题是,通过导航
Document.comments
您才能从技术上获得
Comment
表的查询。然后,当您在
PostComment
表中添加筛选器时,在上下文中不清楚您是否希望假定
Comment
PostComment
之间应该存在一个
join
。如果您将查询更改为下面的内容(也将编辑答案),它应该会执行您真正想要的操作:
query=d1.comments.join(PostComment.join)、filter(PostComment.ready==True)
这正是我想要的。谢谢你,范。它表示“返回此查询将返回的行数”。这在语义上不是错了吗?不是。该查询实际上返回8行。但只有当查询结果转换为映射对象列表时,这才减少到2。真正的问题是,通过导航
Document.comments
您才能从技术上获得
Comment
表的查询。然后,当您在
PostComment
表中添加筛选器时,在上下文中不清楚您是否希望假定
Comment
PostComment
之间应该存在一个
join
。如果您将查询更改为下面的内容(也将编辑答案),它应该会执行您真正想要的操作:
query=d1.comments.join(PostComment.join)、filter(PostComment.ready==True)
这正是我想要的。谢谢你,范。