Help Translate this query into Django ORM
I have a Friendship model with two related user objects associated with it. I would like to write a method that takes a user and returns a list of that user's friends. I was doing it via:
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]
but this incurs a query for every user that is returned in the query set (e.g. hundreds of queries). I could write it via:
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]
but this does an INNER JOIN on the user table. I could also write it via custom 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))
but I was thinking 开发者_C百科there must a way to do it inside the ORM without all those extra lookups. I was trying to do something with id__in
, but I couldn't find a way to get the user ids out of the friends query set.
Assuming you set up your Friendship model similar to the example below and use friend_set
as the related name of the from_friend
field in your model, getting a list of a users friends can be as simple as a basic list comprehension:
friends = [friendship.to_friend for friendship in user.friend_set.all()]
This would even allow you to access a user's friends in your template without having to pass that as a variable:
{% for friendship in user.friend_set.all %}
{{ friendship.to_friend.username }}
{% endfor %}
Your Friendship model would look like this:
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'), )
Here's a great article on building friend networking in Django: http://www.packtpub.com/article/building-friend-networks-with-django-1.0
Note that you shouldn't have to check both from_friend
and to_friend
to get a users friend list. If you have a following/follower friendship model you only need all friendship instances with a from_friend = user, and if you have a double opt-in friendship model you could follow what Facebook does and add an instance for the invited friend as the from_friend
once they accept the friend invite.
精彩评论