I need to check if a user has liked a post on a page that displays all posts, I am passing the posts and user's likes below
def index(request):
if request.method == "POST":
text = request.POST["post-text"]
Post.objects.create(
entity = Entity.objects.create(
user = request.user,
text = text
)
)
return HttpResponseRedirect(reverse("index"))
return render(request, "network/index.html", {
"posts" : Post.objects.all().order_by('-entity__date', '-entity__id'),
"likes" : Like.objects.filter(user = request.user)
})
this is the model
class Entity(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
text = models.TextField()
date = models.DateTimeField(default=datetime.now())
class Like(models.Model):
entity = models.ForeignKey(Entity, on_delete=models.CASCADE, related_name="likes")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="likes")
class Post(models.Model):
entity = models.ForeignKey(Entity, on_delete=models.CASCADE, related_name="post")
Template:
{% for post in posts %}
<div>
<div>{{post.entity.user}}</div>
<div>{{post.entity.text}}</div>
<div>{{post.entity.date}}</div>
<div data-id="{{post.entity.id}}">
{% if post.entity in likes %}
<p>yes</p>
{%else%}
<p>no</p>
{%endif%}
<div >{{post.entity.likes.count}}</div>
</div>
<br />
<a href="#">Comment</a>
<hr />
</div>
{% endfor %}
I don't know how to write the if condition, I've tried this {% if post.entity in likes %} but it doesn't work.
CodePudding user response:
Please don't. While this can be done with such condition, it would result in a lot of extra queries. You can work with a Exists subquery [Django-doc]:
from django.contrib.auth.decorators import login_required
from django.db.models import Exists, OuterRef
from django.shortcuts import redirect
@login_required
def index(request):
if request.method == 'POST':
text = request.POST['post-text']
Post.objects.create(
entity = Entity.objects.create(
user = request.user,
text = text
)
)
return redirect('index')
posts = Post.objects.annotate(
is_liked=Exists(
Like.objects.filter(user=request.user, entity_id=OuterRef('entity_id')
)
).select_related('entity').order_by('-entity__date', '-entity__id')
return render(request, "network/index.html", {
'posts' : posts
})
The Post objects will then have an extra attribute .is_liked that is True if that Post is liked by the logged in user.
Note: You can limit views to a view to authenticated users with the
@login_requireddecorator [Django-doc].
Note: You can make use of
redirect(…)[Django-doc] instead of first callingreverse(…)[Django] and then wrap it in aHttpResponseRedirectobject [Django-doc]. Theredirect(…)function does not only offer a more convenient signature to do this, it also for example will use the.get_absolute_url()method [Django-doc] if you pass it a model object.
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL[Django-doc] to refer to the user model, than to use theUsermodel [Django-doc] directly. For more information you can see the referencing theUsermodel section of the documentation.
Note: Django's
DateTimeField[Django-doc] has aauto_now_add=…parameter [Django-doc] to work with timestamps. This will automatically assign the current datetime when creating the object, and mark it as non-editable (editable=False), such that it does not appear inModelForms by default.
CodePudding user response:
I think it is easier to perform the logic of sorting the Entities/Likes/User inside the view and then pass the correctly formatted data to the template.
This is good practice because soon enough you will want to perform more difficult transformations with the data which will be very hard if not impossible inside the django template. That is also why this kind of logic belongs inside the view.
