Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django query to get User's favorite posts?

I'm a little confused by the Django lingo. So I have 3 models: Post, UserProfile(User), Favorite. Favorite keeps track of which Posts a User has favorited.

Post--->Favorite<---User/UserProfile

Favorite model:

class Favorite(models.Model):
    user = models.ForeignKey(User, unique=False)
    post = models.ForeignKey(Post, unique=False)

    def __unicode__(self):
        return self.user.username

UserProfile model:

class UserProfile(models.Model) :
    user = models.ForeignKey(User, unique=True)

    def get_favorites(self):
        if self.user:
            return self.user.favorite_set.all()

In my post_list view I pass all Posts to my template, and in the template I have a for loop that displays all Posts.

{% for post in post_list %}
<hr/>
<div id=”post_{{ post.id }}”>
    {% include 'posts/_post.html' %}
</div>
{% endfor %}

Now in that for loop I would like to put a logic that will display "Favorited!" if the logged-in User has favorited the Post. I think the conventional SQL is something like this:

SELECT favorite.post FROM favorite WHERE favorite.user = user.id

So that in the template loop I can do

{% if post in the.above.SQL.query%}Favorited!{% endif %}

Now I just can't translate that to Django lingo for some reason. Your help is much appreciated!

like image 510
rabbid Avatar asked Nov 30 '22 16:11

rabbid


1 Answers

The thing to recognise is that your Favorite model is actually the through table of a many-to-many relationship between Post and User. Django can actually manage that automatically if you declare a ManyToManyField somewhere. Personally, I would do that on UserProfile - so the relationship actually becomes one between Post and UserProfile:

class UserProfile(models.Model):
    favorites = models.ManyToManyField(Post, related_name='favorited_by')

Now you don't need your get_favorites method, as it is available via userprofile.favorites.all(). You could just use this as-is in the template:

{% if post in userprofile.favorites.all %}Favorited!{% endif %}

but this will end up being extremely inefficient, as you'll be doing the same identical query for each post in your list of posts. So, use the {% with %} tag to get the favorites once before the loop:

{% with userprofile.favorites.all as favorite_posts %}
  {% for post in post_list %}
    {% if post in favorite_posts %}Favorited{% endif %}
    ...
  {% endfor %}
{% endwith %}
like image 164
Daniel Roseman Avatar answered Dec 06 '22 09:12

Daniel Roseman