0

I have a created two models in my models.py file. I have also created a view and that view renders a template named index.html. I want to show the post and it's likes count in my index webpage/template. but the below code doesn't work.

models.py

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

class Post(models.Model):
    title = models.CharField(max_length=42)
    author = models.ForiegnKey(User, on_delete=models.CASCADE, related_name='author_user')
    create_date = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return f'{self.author.first_name} {self.author.last_name}'

class Like(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='liked_post')
    user = models.Foreignkey(User, on_delete=models.CASCADE, related_name='post_liked_by')

    def __str__(self):
        return f'{self.user.username}@{self.post.title}'

views.py

from django.shortcuts import render
from .models import *

def index(request):
    posts = Post.objects.all()
    likes = Like.objects.all()
    context = {
       'posts': posts,
       'likes': likes,
    }
    return render(request, 'index.html', context)

index.html

<html>
    <head>
        <title>
            Home
        </title>
    </head>
    <body>
        {% for post in posts %}
            <h1>
                {{ post.title }}
            </h1>
            <p>
                Author: {{ post.author.first_name }} {{ post.author.last_name }}
            </p>
            <p>
                Date Created: {{ post.create_date }}
            </p>
            <p>
                <i class="fa fa-heart"></i>
                {{len(likes)}}
            </p>
        {% endfor %}
    </body>
</html>

thank you in advance.

2 Answers2

0

You can access the reverse relation using the _set, so in your template you can do something like and you design it however you want with the css

{% for post in posts %}
    <h1>
        {{ post.title }}
    </h1> 
    <span> Number of likes: {{post.like_set.count()}}</span>

I suggest you go through this https://docs.djangoproject.com/en/3.1/topics/db/queries/

Mohammad Faisal
  • 573
  • 5
  • 13
0

You're returning all the Post objects and all the Like objects independently of each other:

    posts = Post.objects.all()
    likes = Like.objects.all()
    context = {
       'posts': posts,
       'likes': likes,
    }

What you need to use is prefetch_related on the Post object. See the docs here:

So you would do:

posts = Post.objects.prefetch_related('like_set').all()

You can then reference post.like_set in the template. No need to query Like seperately, and now you have the information "joined" the way you need it, rather than 2 distinct data sets that you have trouble connecting in the template.

However in this case, I don't think this is what you actually want to do. You're trying to display the like count, right?

That being the case, I would probably annotate the post query to include a like counter. See the docs for this here if it's suitable for you:

https://docs.djangoproject.com/en/3.1/ref/models/querysets/#django.db.models.query.QuerySet.annotate

But if you actually need the likes info (eg. you're going to display a list of folks that have liked something), then the like_set is the way to go.

michjnich
  • 2,796
  • 3
  • 15
  • 31