Complex query with Django (posts from all friends)

I’m new to Python and Django, so please be patient with me.

I have the following models:

class User(models.Model):
   name = models.CharField(max_length = 50)
   ...

class Post(models.Model):
   userBy = models.ForeignKey(User, related_name='post_user')
   userWall = models.ForeignKey(User, related_name='receive_user')
   timestamp = models.DateTimeField()
   post = models.TextField()

class Friend(models.Model):
   user1 = models.ForeignKey(User, related_name='request_user')
   user2 = models.ForeignKey(User, related_name='accept_user')
   isApproved = models.BooleanField()
   class Meta:
      unique_together = (('user1', 'user2'), )

I know that this may not be the best/easiest way to handle it with Django, but I learned it this way and I want to keep it like this.

Now, all I want to do is get all the post from one person and it’s friends. The question now is how to do it with the Django filters?

I think in SQL it would look something like this:

SELECT p.* FORM Post p, Friend f 
WHERE p.userBy=THEUSER OR (
    (f.user1=THEUSER AND f.user2=p.userBy) OR
    (f.user2=THEUSER AND f.user1=p.userBy)
)

With no guarantee of correctness, just to give an idea of the result I’m looking for.

Best answer

from django.db.models import Q

Post.objects.filter( \
    Q(userBy=some_user) | \
    Q(userBy__accept_user__user1=some_user) | \
    Q(userBy__request_user__user2=some_user)).distinct()

UPDATE

Sorry, that was my fault. I didn’t pay attention to your related_name values. See updated code above. Using userBy__accept_user or userBy__request_user alone won’t work because that’ll be a reference to Friend which you can’t compare to to User. What we’re doing here is following the reverse relationship to Friend and then once we’re there, seeing if the other user on the friend request is the user in question.

This also illustrates the importance of describing reverse relationships appropriately. Many people make the same mistake you’ve made here and name the related_name after the model they’re creating the FK to (User), when actually, when we’re talking about reversing the FK, we’re now talking about Friend. Simply, your related names would make more sense as something like: friend_requests and accepted_friends.