0

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).

Thomas
  • 1
  • 5
  • Which variables not showing? All of them? – James Lin Aug 06 '20 at 03:35
  • indeed, none of them are showing. – Thomas Aug 06 '20 at 03:59
  • Does the template text outside the vars show up? – James Lin Aug 06 '20 at 04:12
  • yes, the text shows like this: "- Stats: plays produced, involving actors, seen by people." And I made sure there are numbers to work with in the Production objects. – Thomas Aug 06 '20 at 04:13
  • Do yourself a test, pass in extra element to the context like `{'test': 'abc'}`, then add that it in your template, see if it shows up. – James Lin Aug 06 '20 at 04:15
  • Also try setting `string_if_invalid` to debug the error https://stackoverflow.com/questions/8990224/make-django-templates-strict – James Lin Aug 06 '20 at 04:19
  • Tried passing {'test': 'abc'} in the context and adding {{ test }} in the template, but even that doesn't show up. Tried the same with another (similar) view in another template in the same location, no problem there!? So strange... – Thomas Aug 06 '20 at 04:22
  • I added `string_if_invalid = 'DEBUG WARNING: undefined template variable [%s] not found` to my settings.py, but it gives no error, though I'm not sure where to look for that possible error, would it give a classic yellow debug page? – Thomas Aug 06 '20 at 04:29

2 Answers2

1

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

Pynchia
  • 10,996
  • 5
  • 34
  • 43
  • I was going to suggest that but he said none of the vars are showing, I would have thought at least `nr_of_plays` should display. – James Lin Aug 06 '20 at 04:05
  • What happens now? I guess the wrong access to those keys might have been preventing the whole to be rendered – Pynchia Aug 06 '20 at 04:09
  • Nah, even pass `Production.objects.all().aggregate(Sum('est_audience'))` to the context, it will still display the queryset repr, but he says nothing shows up, but that's also confusing, does he mean even the templated text also not showing up? – James Lin Aug 06 '20 at 04:11
1

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.

James Lin
  • 25,028
  • 36
  • 133
  • 233