0

因此,在阅读SQLAlchemy ordering by count on a many to many relationship之后,我尝试复制结果,但它无法正常工作。所以我的模型是

class Group(Base):
__tablename__='groups'
__table_args__={
    'mysql_engine':'InnoDB',
    'mysql_charset':'utf8',
}

id = Column(Integer, primary_key=True, unique=True)
name = Column(VARCHAR(30), primary_key=True, unique=True)
time = Column(DateTime, onupdate = datetime.datetime.now)
description = Column(VARCHAR(255))
creator_id = Column(Integer, ForeignKey('users.id'))
privacy = Column(SMALLINT) # 0 == public, 1 == friends, 2 == private

def __init__(self, name, descr, creator, privacy):
    self.name = name
    self.description = descr
    self.creator_id = creator
    self.privacy = privacy

class GroupUserRelationship(Base):
__tablename__='groupUserRelationships'
__table_args__={
    'mysql_engine':'InnoDB',
    'mysql_charset':'utf8',
}

id = Column(Integer, primary_key = True)
group_id = Column(Integer, ForeignKey('groups.id'))
user_id = Column(Integer, ForeignKey('users.id'))
time = Column(DateTime, onupdate=datetime.datetime.now)

def __init__(self, group, user):
    self.group_id = group
    self.user_id = user

我的 sqlalchemy 查询是groups = session.query(Group, func.count(GroupUserRelationship.user_id).label('total')).join(GroupUserRelationship).group_by(Group).order_by('total DESC').limit(20).all(),但是当我尝试遍历它返回的列表并访问组 id 时,我得到一个 AttributeError:'NamedTuple' 没有属性 id。怎么了?

4

1 回答 1

2

这种形式的查询:

session.query(Group, func.count(GroupUserRelationship.user_id).label('somelabel'))

将返回一个像这样的元组列表:

[
    (group1, 5),
    (group2, 7),
    ...
]

.. ETC。

然后迭代到 group.id 是:

for group, user_id in session.query(Group, func.count(GUR.user_id).label('somelabel')).join(...):
    print group.id

对于计数,我认为重要的第一个技巧是养成不按整行分组的习惯(即 group_by(Group))。虽然可以使用该技术使此处的查询工作,但这是不好的做法,因为您正在使数据库执行大量额外的工作来匹配整个组表的所有列,而实际上您需要分组的是单列 GroupUserRelationship.user_id . 我参考这篇文章http://weblogs.sqlteam.com/jeffs/archive/2005/12/14/8546.aspx对此进行了一些阐述。SQLAlchemy 教程随后在此处提供了此表单的示例:http: //docs.sqlalchemy.org/en/rel_0_7/orm/tutorial.html#using-subqueries

在 SQLAlchemy 中真正有用的下一件事是使用 relationship() 在两个类之间建立特定的连接路径。所以这就是使用子查询完成的分组表达式。此处使用的特殊技巧是可选的,您可以说join(subquery, Group.gur)“使用 Group.gur 关系的等效连接条件连接到此子查询”。

编辑以说明完整的往返示例

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Group(Base):
    __tablename__ = 'groups'

    id = Column(Integer, primary_key=True)
    name = Column(VARCHAR(30))
    gur = relationship("GroupUserRelationship")

class GroupUserRelationship(Base):
    __tablename__ = 'groupUserRelationships'

    id = Column(Integer, primary_key=True)
    group_id = Column(Integer, ForeignKey('groups.id'))

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)

s.add_all([
    Group(name='g1', gur=[GroupUserRelationship() for i in xrange(3)]),
    Group(name='g2', gur=[GroupUserRelationship() for i in xrange(8)]),
    Group(name='g3', gur=[GroupUserRelationship() for i in xrange(5)]),
    Group(name='g4', gur=[GroupUserRelationship() for i in xrange(1)]),
    Group(name='g5', gur=[GroupUserRelationship() for i in xrange(2)]),
])
s.commit()


gur_count = s.query(
                func.count(GroupUserRelationship.id).label('total'),
                GroupUserRelationship.group_id
            ).group_by(GroupUserRelationship.group_id).\
            subquery()

for group, gur_count in s.query(Group, gur_count.c.total).\
            join(gur_count, Group.gur).\
            order_by(gur_count.c.total):
    print "GROUP:", group.name, "GROUP ID:", group.id, "NUMBER OF GUR:", gur_count

输出(减去 SQL 回显,这对于查看正在发生的事情很有用):

GROUP: g4 GROUP ID: 4 NUMBER OF GUR: 1
GROUP: g5 GROUP ID: 5 NUMBER OF GUR: 2
GROUP: g1 GROUP ID: 1 NUMBER OF GUR: 3
GROUP: g3 GROUP ID: 3 NUMBER OF GUR: 5
GROUP: g2 GROUP ID: 2 NUMBER OF GUR: 8
于 2012-09-09T17:11:38.517 回答