0

I have a auth_user model, and a posts model. the posts model has fields like: id, author_id and likes. All I need print likes values related to each user in the base template. like:

{{ user.posts.likes }}

or

{{ user.user_id.posts.likes }}

This is my posts model:

class Post(models.Model):
    title = models.CharField(max_length=150)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    likes = models.PositiveIntegerField(default=0, blank=True)
    
    class Meta:
        db_table = "posts"
    
    def total_likes(self):
        return self.likes

however it does not work, while {{ user.profile.image.url }} (profile is another model which has user_id) works perfectly. I am importing base templates to other templates like {% extends "app/base.html" %} so I don't see any place in backend to pass the likes values

ElisaFo
  • 130
  • 13

1 Answers1

1

I believe the problem is that you're confusing a single Post for multiple posts and as a result there isn't an object to access. A user only has one profile, but as your code indicates they can have multiple posts as the author ForeignKey would indicate.

{{ user.post_set }} <- is a manager
{{ user.post_set.all }} <- is a queryset
{{ user.post_set.all.0 }} <- is the first item of the queryset 
{{ user.post_set.all.0.likes }} <- should be the # of likes of the user's first post

Edit 1

The updated question could be restated as "how can I get the total number of likes a user has received via their posts"

There might be a way to accomplish that in the templates, but I think it's going to be difficult. I would put that number together in the view code. The key word that you're looking for is "aggregation"

https://docs.djangoproject.com/en/3.1/topics/db/aggregation/

from django.db.models import Sum
...
# inside your view
total_likes = user.post_set.all().aggregate(Sum('likes'))

Edit 2

Absolutely right @melvyn

Edit 3

In order to apply this to all pages without modifying the views you're going to have to write a context processor.

https://docs.djangoproject.com/en/3.1/ref/templates/api/#writing-your-own-context-processors

file: likes_context.py
from django.db.models import Sum

def likes_context_processor(request):
    if request.user.is_authenticated:
        posts = request.user.post_set.all()
        total_likes = posts.aggregate(Sum('likes'))
    else:
        total_likes = 0
    return {"total_likes": total_likes }

You'll need to locate that file appropriately and then add it to your context processors config in your settings.py

This might be helpful as well: creating my own context processor in django

Mike Sandford
  • 1,315
  • 10
  • 22
  • Hi Mike, Thank you for your answer, I tried `{{ user.posts.all.0.likes }} `, `{{ user.posts.all.0.title }}`, `{{ user.posts.all.0}}`,`{{ user.posts.all }}` and non of them return any result. Just `{{ user }}` returns the value of `username` – ElisaFo Oct 25 '20 at 18:18
  • I just tried with `{{ posts.0.likes }}` and it returns the number of likes based on the first post of querysets which I passed to each template in the views.py. For example in first template 11, second 0, third 200 and so on... do you know how can I expect to sum up all likes of posts which user created? I tried with `{{ user.posts.all.likes |length }}` and didn't work! – ElisaFo Oct 25 '20 at 20:16
  • 2
    Pssst: there is no `related_name`, so user.posts should be `user.post_set`. –  Oct 25 '20 at 20:47
  • @Mike Thanks for your update. As I am using likes in the header in base.html so I am not passing posts.queryset directly to base template so I guess I can't handle it in view.py. Do you know how to solve it in template? – ElisaFo Oct 25 '20 at 21:06
  • @Mike Your answer is brilliant. It's working as I expect just one error occurs when I am trying to log out. as `'AnonymousUser' object has no attribute 'post_set'` which happens in the line `posts = request.user.post_set.all()` I tried to put skip it but all the code goes crazy even after shutting down the server which is weird! – ElisaFo Oct 25 '20 at 21:53
  • Just updated to take that into account. I guess I had assumed that everyone would be logged in to be able to see the page. Just add a check for user.is_authenticated – Mike Sandford Oct 26 '20 at 10:18