【问题标题】:SQLAlchemy order by relationships in mapper tableSQLAlchemy 按映射表中的关系排序
【发布时间】:2012-08-27 13:31:41
【问题描述】:

所以在阅读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。怎么了?

【问题讨论】:

    标签: sqlalchemy


    【解决方案1】:

    这种形式的查询:

    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() 在两个类之间建立特定的连接路径。所以这就是使用子查询完成的分组表达式。这里使用的特殊技巧是可选的,您可以说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
    

    【讨论】:

    • 有没有办法订购它们?
    • 元组似乎不包含组 ID。当我打印对查询的响应时,我得到一个元组,其中包含:[(, 1L), (, 2L)]
    • (, 1L) 不是“元组”。访问模式是我之前提到的“for group, group_id in s.query(...)”
    • 查询似乎只返回了关系最多的顶层组;这是我的查询:gur_count = session.query(func.count(GroupUserRelationship.id).label('total'), GroupUserRelationship.group_id).group_by(GroupUserRelationship.group_id).subquery() for group, user_id in session.query(Group, gur_count.c.total).join(gur_count, Group.gur).order_by(gur_count.c.total).all(): 然后我打印了 for 循环的所有结果,我得到的只是['asdf', 1L],当名称是第一个元素时。
    • 我已经编辑了脚本以包含一个工作往返示例;请准确复制并运行它以了解其工作原理,然后再确定您正在运行的示例有何不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-03
    • 2013-09-19
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 2019-04-07
    • 1970-01-01
    相关资源
    最近更新 更多