0

そのため、 SQLAlchemy の多対多関係のカウントによる順序付けを読んだ後、結果を複製しようとしましたが、正しく機能していません。だから私のモデルは、

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' Does not have attribute id. 何がうまくいかないのですか?

4

1 に答える 1

2

この形式のクエリ:

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

次のようなタプルのリストを返します。

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

...など

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() を使用して、2 つのクラス間に特定の結合パスを確立することです。サブクエリを使用してグループ化式を実行すると、次のようになります。ここで使用されているオプションの特定のトリックは、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 に答える