So after reading SQLAlchemy ordering by count on a many to many relationship, I tried to replicate the result, but it’s not working correctly. So my models are,
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
and my sqlalchemy query is groups = session.query(Group, func.count(GroupUserRelationship.user_id).label('total')).join(GroupUserRelationship).group_by(Group).order_by('total DESC').limit(20).all(), but when I try to iterate over the list that it returns and access the group id, I get an AttributeError: ‘NamedTuple’ Does not have attribute id. Whats going wrong?
a query of this form:
will return a list of tuples like this:
.. etc.
Iteration to get at group.id is then:
For the count, the first technique that I feel is important is to get into the habit of not grouping by an entire row (i.e. group_by(Group)). While the query here can be made to work using that technique, it’s poor practice because you are making the database do lots of extra work matching all the columns of the entire group table, when really all you need grouped is the single column GroupUserRelationship.user_id. I refer to this article http://weblogs.sqlteam.com/jeffs/archive/2005/12/14/8546.aspx for some exposition on that. The SQLAlchemy tutorial then features an example of this form here: http://docs.sqlalchemy.org/en/rel_0_7/orm/tutorial.html#using-subqueries .
The next thing that works really great in SQLAlchemy is to use a relationship() to establish a particular join path between two classes. so here is that, with the grouping expression done using the subquery. The particular trick used here, which is optional, is that you can say
join(subquery, Group.gur)which means “join to this subquery using the equivalent join condition of the Group.gur relationship”.edited to illustrate a full round trip example
output (minus SQL echoing, which is useful to see what’s going on):