帮助将此查询转换为Django ORM

时间:2011-07-29 23:22:45

标签: python sql django orm

我有一个友谊模型,其中有两个与之关联的相关用户对象。我想写一个方法,它接受用户并返回该用户的朋友的列表。我这样做是通过:

 friends = Friendship.objects.filter(Q(user1=user) | Q(user2=user))
 friends_list = [f.user1 if user == f.user2 else f.user2 for f in friends]

但这会导致查询集中返回的每个用户的查询(例如数百个查询)。我可以通过以下方式写出来:

 friends = Friendship.objects.select_related().filter(Q(user1=user) | Q(user2=user))
 friends_list = [f.user1 if user == f.user2 else f.user2 for f in friends]

但是这会在用户表上执行INNER JOIN。我也可以通过自定义SQL编写它,

 friends = User.objects.raw("""
            SELECT * FROM usertable WHERE id IN (SELECT
            user1_id FROM friendstable WHERE user2_id=%d) OR id IN 
            (SELECT user2_id FROM lists_friendship WHERE user1_id=%d);
            """ % (user.pk, user.pk))

但我认为必须有一种方法可以在ORM内部进行,而无需进行所有额外的查找。我试图用id__in做一些事情,但我找不到从朋友查询集中获取用户ID的方法。

1 个答案:

答案 0 :(得分:0)

假设您设置的友谊模型与下面的示例类似,并使用friend_set作为模型中from_friend字段的相关名称,获取用户朋友列表可以简单到一个基本的列表理解:

friends = [friendship.to_friend for friendship in user.friend_set.all()]

这甚至允许您在模板中访问用户的朋友,而不必将其作为变量传递:

{% for friendship in user.friend_set.all %}
    {{ friendship.to_friend.username }}
{% endfor %}

您的友谊模型如下所示:

class Friendship(models.Model):
  from_friend = models.ForeignKey(
    User, related_name='friend_set'
  )
  to_friend = models.ForeignKey(
    User, related_name='to_friend_set'
  )
  def __unicode__(self):
    return u'%s, %s' % (
      self.from_friend.username,
      self.to_friend.username
    )
  class Meta:
    unique_together = (('to_friend', 'from_friend'), )

这是一篇关于在Django中构建朋友网络的精彩文章: http://www.packtpub.com/article/building-friend-networks-with-django-1.0

请注意,您不必同时检查from_friendto_friend以获取用户好友列表。如果您有以下/关注者友谊模型,您只需要所有友情实例与from_friend = user,如果您有双重选择友谊模型,您可以按照Facebook所做的操作,并为受邀朋友添加一个实例{{{ 1}}一旦他们接受了朋友的邀请。