如何使用SQLAlchemy ORM构造查询

时间:2013-02-18 16:09:42

标签: python mysql sqlalchemy

我有3个看起来像这样的模型(简化):

用户:

id
username

资源:

id
name
description

注释:

id
user_id (relationship User)
resource_id (relationship Resource)
data
date_created

我正在尝试查询用户的评论并按资源对其进行分组。我希望结果回来: [(资源A,[评论,评论,评论,......]),(资源B,[评论,评论,......]),(资源X,[评论])]

我已经尝试了各种方法来构建它,我似乎无法弄明白。做这样的事情的正确方法是什么?

修改

现在代码看起来像这样:

contrib = db_session.query(Resource).filter(Comment.user==user, Resource.uuid==Comment.resource_id).distinct(Comment.resource_id).order_by(desc(Comment.date_created))
comments = db_session.query(Comment, Resource).filter(Comment.user==user, Comment.resource_id.in_([r.uuid for r in contrib]), Resource.uuid==Comment.resource_id).order_by(desc(Comment.date_created))

然后我使用一些列表/字典理解将这些结果组合成看起来像

的东西
[{resource: Resource, comments:[Comment, Comment, Comment]}, {resource: Resource, comments:[Comment, .....]}, .....]

必须有更好的方法来做到这一点!

2 个答案:

答案 0 :(得分:1)

您可以使用自定义MappedCollection对评论进行分组:

from sqlalchemy.orm.collections import collection, MappedCollection

class GroupedCollection(MappedCollection):

  def __init__(self):
    super(GroupedCollection, self).__init__(
      self,
      lambda e: e.resource_id # the key we want to group by
    )

  @collection.internally_instrumented
  def __setitem__(self, key, value, _sa_initiator=None):
    if key in self:
      # there is already another comment for that resource
      # we simply append the comment (or you could do something
      # more fancy here if you would like to order the comments)
      self[key]['comments'].append(value)
    else:
      # we create a new entry with a dictionary containing the
      # resource and comment
      super(GroupedCollection, self).__setitem__(
        key,
        {'resource': value.resource, 'comments': [value]},
        _sa_initiator
      )

然后在User班级添加相应的关系:

class User(Base):

  # ...

  grouped_comments = relationship(
    'Comment',
    collection_class=GroupedCollection
  )

访问它将为您提供按资源分组的评论:

>>> user.grouped_comments
{
  'resource_id_1': {'resource': <Resource 1>, 'comments': [<Comment ...>, <Comment ...>]},
  'resource_id_2': {'resource': <Resource 2>, 'comments': [<Comment ...>]}
}
>>> user.grouped_comments.values()
[
  {'resource': <Resource 1>, 'comments': [<Comment ...>, <Comment ...>]},
  {'resource': <Resource 2>, 'comments': [<Comment ...>]}
]

请注意,此关系仅应用于查看相关模型,启用添加/删除模型需要额外的工作。

最后,如果这是您想要重现的模式,您可以轻松创建GroupedCollection工厂函数,您可以在其中指定分组键。

答案 1 :(得分:0)

请查看演示:http://sqlfiddle.com/#!2/9f2ea/2

希望这有帮助