0

I want to get a variable on the views.py file that retrieves the list of likes for each post. So, then on the HTML file, I would use .count so I can get the number of items on the list and finally be displayed on the DOM.

I first made classes on models.py. There, I have 3 classes: User, Post, and Like. User is from the default User class from Django. Post is a class that gets information about the post like the author, description, and timestamp. And on the Like class, I get the user and post.

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    pass

class Post(models.Model):
    author = models.ForeignKey("User", on_delete=models.CASCADE, related_name="user")
    description = models.CharField(max_length=1000)
    timestamp = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return f"{self.id}: {self.author}"

class Like (models.Model):
    user = models.ForeignKey("User", on_delete=models.CASCADE, default='', related_name="user_like")
    post = models.ForeignKey("Post", on_delete=models.CASCADE, default='', related_name="post_like")
    def __str__(self):
        return f"{self.id}:{self.user} likes {self.post}"

Second, I made a function on views.py called "index". There, I get the whole list of posts (on the posts variable), then I tried to create the variable (totalLikesSinglePost), which should get the list of likes for each post.

def index(request):
    posts = Post.objects.all().order_by("id").reverse()

    # Pagination Feature (OMIT THIS, IF YOU WANT)
    p = Paginator(posts, 10)
    pageNumber = request.GET.get('page')
    postsPage = p.get_page(pageNumber)

    # Total likes of each post. DOESN'T WORK ⏬
    for postSingle in posts: 
        totalLikesSinglePost = Like.objects.all().filter(post = postSingle)

    return render(request, "network/index.html", {
        "posts": posts,
        "postsPage": postsPage,
        "totalLikesPost": totalLikesSinglePost
    })

Finally, on the HTML file, there I get each post with its information and the number of likes. However, the output just displays the number 0

    {% for post in postsPage %}
    <div class="row">
        <div class="col">
            <div class="card h-100" id="post-grid">
                <div class="card-body">
                    <h5>{{ post.author }}</h5>
                    <div> | {{ post.timestamp }}</div>
                    <p>{{ post.description }}</p>
                    <div class="card-buttonsContainer">
                        <strong style="color: red">{{ totalLikesPost.count }}</strong> <!--0 IS DISPLAYED-->
                    </div>
                </div>
            </div>
        </div>
    </div>
    {% endfor %}    

And of course, after that, I created a superuser and went to admin to add some examples to the database. However, I added some new rows on the Like table but does not display the total of likes for each post.

Kmi4444
  • 5
  • 2

2 Answers2

0

Your totalLikesSinglePost is just a list of Like records of the last post. Try this on your html file:

<strong style="color: red">{{ post.post_like.count }}</strong>
  • Thanks so much. The problem is fixed. However, I am curious to know the reason behind that. Can you please tell me what is 'post_like'? I'm asking this because 'post_like' is not a column inside the Post table. So, where did you get it? – Kmi4444 Dec 16 '22 at 15:48
  • Because on the ```post``` field on the ```Like``` model you define ```related_name=post_like```, so when you have one object on the ```Post```, example ```Post1```, you can get all the ```Like``` object that related to Post 1 by using ```post1.post_like```. For more, check it out here: https://stackoverflow.com/questions/2642613/what-is-related-name-used-for – Valentinooo Dec 28 '22 at 02:19
0

Because totalLikesSinglePost get override in each round of for loop. It is the total number of likes of the last post.

You need to assign this number to the post as an attribute, like

for post in posts:
    post.num_likes = Like.objects.all().filter(post=post).count()

And then in your template

{% for post in posts %}
    {# ... #}
    {{ post.num_likes }}
{% endfor %}

However, I strongly recommend you using .annotate

from django.db.models import Count

posts = Post.objects.all().order_by('-id')\
    .annotate(num_likes=Count('like'))

This will access database only once and save you a lot of time.

Ezon Zhao
  • 577
  • 2
  • 14