Reputation: 25
I have passed the context of is_liked to from the PostListView to the home template, but why the if post.is_liked
the statement doesn't work? I have an like_post
function that when the user liked the post, the is_liked will equal to true
and text will turn from not liked to liked. But why the if statements did not work(only showed not liked) in the template with no error messages? Or I have tried to change the if statements to {% post.user.is_liked %}
and {% user.is_liked %}
. But it still didn't work, what is the problem? thanks
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(User, related_name='likes', blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
views.py
def home(request):
context = {
'posts': Post.objects.all(),
}
return render(request, 'blog/home.html', context)
def like_post(request): # post like
post = get_object_or_404(Post, id=request.POST.get('post_id'))
is_liked = False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
is_liked = False
else:
post.likes.add(request.user)
is_liked = True
return HttpResponseRedirect(post.get_absolute_url())
class PostListView(ListView):
model = Post
template_name = 'blog/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 10
is_liked = False
def get_context_data(self, *, object_list=None, **kwargs):
context = super(PostListView, self).get_context_data()
posts = context['posts']
for post in posts:
if post.likes.filter(id=self.request.user.id).exists():
context['is_liked'] = True
return context
class PostDetailView(DetailView):
model = Post
is_liked = False
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
post = context['post']
if post.likes.filter(id=self.request.user.id).exists():
context['is_liked'] = True
return context
home.html
{% for post in posts %}
<form action="{% url 'like_post' %}" method="post">
{% csrf_token %}
{% if post.is_liked %} #I want to get whether the post is_liked by user
<h5>liked</h5>
{% else %}
<h5>not liked</h5>
{% endif %}
</form>
{% endfor %}
Upvotes: 1
Views: 153
Reputation: 476709
You can annotate the queryset such that the Post
objects that arise from this have an extra attribute .is_liked
with an Exists
subquery [Django-doc]:
from django.db.models import Exists, OuterRef
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 10
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).annotate(
is_liked=Exists(Post.likes.through.objects.filter(
user_id=self.request.user.id,
post_id=OuterRef('pk')
))
)
Upvotes: 1