2011-07-19 22 views
3

我使用Django编写社交网络应用程序,并且需要实现类似于Facebook“共同朋友”概念的功能。我有这样一个简单的模型:Django:根据交叉对象的数量订购商品(共同朋友)

class Friend(models.Model): 
    user = models.ForeignKey(User) 
    guid = models.BigIntegerField() 
    name = models.TextField() 

    class Meta: 
     unique_together = ['user', 'facebook_id'] 

它代表我的网站的用户,和他的一个朋友之间的关系。 (朋友们不一定也是用户)的共同的朋友两个用户之间的数字可以作为他们的朋友名单的交集来计算,换言之,

users = User.objects.all() 
friends = Friend.objects.filter(user=request.user) 
friend_ids = [f.guid for f in friends] 
for user in users: 
    user.mutual = Friend.objects.filter(user=user, guid__in=friend_ids).count() 

(做的更有效的方法上面将比分积分)。

我的主要问题是,计算了用户之间的共同朋友数量,我怎么现在可以根据当前用户的共同朋友数量来订购users queryset?在这种情况下,我不能将计数保存为注释或额外字段,因为它依赖于正在检查的特定用户以及他的全部朋友的特定子集。我能否以一种巧妙的方式使用annotateextra方法?或者是一个raw sql查询的唯一途径?如果是这样,怎么样?

总结

计算的共同朋友的数量为每个用户是没有问题的。鉴于每个用户的信息,那么您如何根据该号码订购QuerySet

回答

2

不知道这是你在寻找什么,但...

# get current users friends (assuming guid is unique for a friend?) 
user_friend_guids = Friend.objects.values_list('guid', flat=True).filter(user=user) 

# get Friend objects where user not current user, is in user_friend_list, group and count by user 
mutual_friends = Friend.objects.values('user__username') \ 
           .filter(guid__in=user_friend_guids).exclude(user=user) \ 
           .annotate(number_mutual_friends=Count('user')) \ 
           .order_by('-number_mutual_friends') 

将返回用户名的列表与朋友,他们与用户共享的数量,由他们分享的次数进行排序。

然后在模板:

{% for mutual_friend in mutual_friends %} 
    {{mutual_friend.user__username}} - {{mutual_friends.number_mutual_friends}} 
{% endfor %} 
+0

恐怕不太我正在寻找:我期待以便根据其共同的朋友数量User's对象'名单,而不是朋友的对象。我知道一个小小的区别,但这是给用户带来麻烦的排序。为了澄清,'用户'对象是正常的Django后端'用户'对象,而'朋友'定义如上,并不代表实际用户,只是我用户的联系人列表中的人员。 –

+0

好的,为了澄清以上不会返回Friend对象。它会以[{“user__username”:james,“number_mutual_friends”:10},{“user__username”:herman,“number_mutual_friends”:6}]的格式返回一个列表,所以您将得到用户名列表(或字段你选择),但是,正如你提到的不是用户对象。如果它必须是用户对象,我认为(其他人可能会回答)它需要通过原始SQL或将共同朋友定义为通过python的方法和顺序来完成eHttp://stackoverflow.com/questions/981375/using -a-django-custom-model-method-property-in-order- – JamesO

+0

好的,谢谢。不幸的是,订购python不会成为一种选择,因为可能有10000多个用户。但是,是的,现在想想看,你的方法看起来可能是所有必要的。我会多玩一会儿,然后回来(希望能有一个解决方案)。谢谢! –