How to count row from backref in template?

I have a question. I need to count MemePositiveRating for Meme in template.
I try meme.memeratingpositive|length but not working.
There is any idea to do it with Abstract layer in models ? Here are my scripts:

home.html:

<a class="mr-2" href="#">{{ meme.memeratingpositive|length }}</a>

models.py:

class Meme(models.Model):
    title = models.CharField(max_length=100)
    meme = models.ImageField(upload_to='memes')
    creation_date = models.DateField(default=timezone.now)
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)

    def __str__(self):
        return f'Meme id: {self.id}'

class MemeRating(models.Model):
    meme = models.ForeignKey(Meme, on_delete=models.CASCADE, related_name = 'ratings', blank = True, null = True)
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)

    class Meta:
        abstract: True

class MemeRatingPositive(MemeRating):
    pass
    
class MemeRatingNegative(MemeRating):
    pass

views.py:

class HomeView(ListView):
    template_name = 'meme/home.html'
    model = Meme
    context_object_name = 'memes'
    
    def get_queryset(self):
        return Meme.objects.filter(memestatus__is_in_moderating_room=False, memestatus__is_in_waiting_room=False)

>Solution :

Instead of the current model structure, I would suggest like this:

class Meme(models.Model):
    title = models.CharField(max_length=100)
    meme = models.ImageField(upload_to='memes')
    creation_date = models.DateField(default=timezone.now)
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)

    def __str__(self):
        return f'Meme id: {self.id}'

class MemeRating(models.Model):
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)

    class Meta:
        abstract: True

class MemeRatingPositive(MemeRating):
    meme = models.ForeignKey(Meme, on_delete=models.CASCADE, related_name = 'memeratingpositive', blank = True, null = True)
    
class MemeRatingNegative(MemeRating):
    meme = models.ForeignKey(Meme, on_delete=models.CASCADE, related_name = 'memeratingnegative', blank = True, null = True)

Then you can call in the template like this:

{{ meme.memeratingpositive.count }}

Here I changed the related name for both of the Negative and Positive Memes model class.

Apart from that, I think the meme rating model should not have multiple tables, instead ratings can be stored in same MemeRating model, and use Enum to determine its positive or negative. In that way, you would not have to change too much when you want different expression other than positive or negative. Here is how I would suggest:

class Meme(models.Model):
    title = models.CharField(max_length=100)
    meme = models.ImageField(upload_to='memes')
    creation_date = models.DateField(default=timezone.now)
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)

    def __str__(self):
        return f'Meme id: {self.id}'

    @property
    def positive_ratings_count(self):
        self.rating.filter(expression_type="POS").count()

    @property
    def negative_ratings_count(self):
        self.rating.filter(expression_type="NEG").count()

class MemeRating(models.Model):
    CHOICES= [
        ("POS", "Positive"),
        ("NEG", "Negative"),
    ]
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
    meme = models.ForeignKey(Meme, on_delete=models.CASCADE, related_name = 'rating', blank = True, null = True)
    expression_type = models.CharField(max_length=3, choices=CHOICES, default="POS")

Then use it in template:

{{ meme.positive_rating_count }}

Leave a Reply