Thomas
Thomas

Reputation: 1

django - Count objects and sum values in a field

I want to include some basic statistics about a model in a stats.html file. The variables don't show in the html. What am I doing wrong?

from django.shortcuts import render, get_object_or_404, redirect
from django.db.models import Avg, Sum, Count
from .models import Production

def statistics(request):
    nr_of_plays = Production.objects.count()
    nr_of_actors = Production.objects.aggregate(num_actors=Sum('nr_actors'))
    nr_of_audience = Production.objects.aggregate(num_audience=Sum('est_audience'))
    context = {
        'nr_of_plays': nr_of_plays,
        'nr_of_actors': nr_of_actors['num_actors'],
        'nr_of_audience': nr_of_audience['num_audience'],
        'test':'abc'
    }
    return render(request, 'stats.html', context)

The model:

class Production(models.Model):
    title = models.CharField(max_length=200)
    nr_actors = models.IntegerField(default=0)
    est_audience = models.IntegerField(default=0)
    ...

urls.py:

path('stats/', views.statistics, name='stats'),

the relevant section of base.html:

<copyright class="text-muted">
    <div class="container text-center">
        <p>&copy; One World Theatre - {% now "Y" %} {% include 'stats.html' with test=test %}  </p>
    </div>
</copyright>

And the stats.html template:

{% load static %}

{{ test }} - Stats: {{ nr_of_plays }} plays produced, involving {{ nr_of_actors }} actors, seen by {{ nr_of_audience }} people.

the output: © One World Theatre - 2020 - Stats: plays produced, involving actors, seen by people.

EDIT:

I didn't mention that I'm using my template stats.html in my base.html template like this {% include 'stats.html' %}. When I add with test=test to the include tag, the test text shows. But when adding with nr_of_plays=nr_of_plays nothing happens :-/.

I ended up forgetting about trying to {% include 'stats.html' %} in my base template and just added those variables where I need them, works great. Not DRY, but what to do... .

EDIT 2:

I was too quick to cry victory. Edited the question with the latest code. Passing the variables in the view that handles the main content block works, but that means I would have to add them in every single view (not DRY). Still not getting what doesn't work with my setup. example.com/stats.html renders exactly what I want, but doesn't show the variables when I include it in my base.html. with test=test doesn't do anything. Clueless (and thankful for the help sofar).

Upvotes: 0

Views: 743

Answers (2)

James Lin
James Lin

Reputation: 26538

Base on your latest confession and symptoms, you don't seem to be going to your statistics view.

Looks like the url is rendering another view, which also extends base.html confuses you that you are in the right view.

One way to test it is to put a print statement in your statistics view and see if it prints anything in the console:

def statistics(request):
    print(111111111111111111111111111111)
    ...
    return render(request, 'stats.html', context)

Second thing is, if your base.html includes stats.html, you shouldn't be rendering the stats.html directly, you should pass the context to a template that extends base.html.

Third thing is, refer to Pynchia's answer to properly get the count of aggregated queryset.

Upvotes: 1

Pynchia
Pynchia

Reputation: 11590

Aggregate returns a dictionary.

You need to access its value via the key

context = {
        'nr_of_plays': nr_of_plays,
        'nr_of_actors': nr_of_actors['nr_actors_sum'],
        'nr_of_audience': nr_of_audience['est_audience_sum']
    }

Alternatively you can specify a custom key name instead of the default composite one:

    nr_of_actors = Production.objects.aggregate(num_actors=Sum('nr_actors'))
    nr_of_audience = Production.objects.aggregate(num_audience=Sum('est_audience'))

Note: .all() is redundant and can be removed

Upvotes: 1

Related Questions