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_required
decorator [Django-doc].
Note: You can make use of
redirect(…)
[Django-doc] instead of first callingreverse(…)
[Django] and then wrap it in aHttpResponseRedirect
object [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 theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model 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 inModelForm
s 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.