How do I grab each model object from a ListView? I have a blog and I'm trying to order each post's comments by the number of comment likes
views.py
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 5
def get_context_data(self, *args, **kwargs):
com = Comment.objects.filter(post=self.object?) #<--- WHAT TO INPUT HERE?
comment_list = com.annotate(like_count=Count('liked')).order_by('-like_count')
#BELOW DOESN'T WORK. EVERY POST HAS THE SAME COMMENT LIST AS THE LATEST POST.. SEE PICTURE BELOW
# posts = Post.objects.all()
# for post in posts:
# com = Comment.objects.filter(post=post) #<--- what to input here
# comment_list = com.annotate(like_count=Count('liked')).order_by('-like_count')
#BELOW DOESN'T WORK. EVERY POST HAS THE SAME COMMENT LIST AS THE LATEST POST.. SEE PICTURE BELOW
# posts = Post.objects.all()
# #for post in posts:
#comment_list = post.comment_set.all().annotate(like_count=Count('liked')).order_by('-like_count')
context = super(PostListView, self).get_context_data(*args, **kwargs)
context['cats_menu'] = cats_menu
context['c_form'] = c_form
context['comment_list'] = comment_list
return context
img link - all other posts copy the comments on the latest post
models.py
class Comment(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
body = models.TextField(max_length=300)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
liked = models.ManyToManyField(Profile, blank=True, related_name='com_likes')
def __str__(self):
return f"Comment:{self.user}-{self.post}-{self.id}"
def post_id(self):
return self.post.id
def num_likes(self):
return self.liked.all().count()
class CommentLike(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
comment = models.ForeignKey(Comment, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, max_length=8)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f" | CommentLike({self.user}-{self.comment}-{self.value})"
template
{% for comment in comment_list %}
CodePudding user response:
You can use Dynamic filtering to specify ListView.get_queryset along with a Prefetch object
view
class PostListView(ListView):
model = Post
template_name = "blog/home.html"
context_object_name = "posts"
ordering = ["-date_posted"]
paginate_by = 5
def get_queryset(self):
return (
super()
.get_queryset()
# Prefetch comment using a Prefetch object gives you more control
.prefetch_related(
Prefetch(
"comment",
# Specify the queryset to annotate and order by Count("liked")
queryset=Comment.objects.annotate(
like_count=Count("liked")
).order_by("-like_count"),
# Prefetch into post.comment_list
to_attr="comment_list",
)
)
)
template
{% for post in posts %}
{% for comment in post.comment_list %}
{{ comment.like_count }}
{% endfor %}
{% endfor %}