0

I am new to Django but have been around RdB for a while. I am finally getting the hang of model-view-template. I am struggling a little on "aggregate" and "annotate" especially when my model has grand-child records and I want aggregate.

I use Django 3 on Python 3. Here is my example setup, I need help straightening it out. I am all sorts of wrong.

There are stores, each that served many pizzas, each pizza has many toppings, each topping used a different qty of items. I want to know the total topping qty for each pizza made and for total topping qty for each store.

models.py

class Parlor(models.Model):
   name = models.CharField(max_length=64)

class Pizza(models.Model):
   name = models.CharField(max_length=64)
   store = models.ForeignKey(Parlor, on_delete=models.CASCADE)

class Topping(models.Model):
   name = models.CharField(max_length=64)
   pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE) 
   qty = models.IntegerField(default=0)

views.py

class ParlorDetail(generic.DetailView):
    model = Parlor
    template_name = 'pizza/parlor_detail.html'
    context_object_name = 'parlor'
    def get_context_data(self, **kwargs):
        context = super(ParlorDetail, self).get_context_data(**kwargs)
        id = self.kwargs['pk']
        topping_qty = Pizza.objects.filter(parlor=id).annotate(sum=Sum('qty')).aggregate(sum=Sum('qty'))
        return context

class PizzaDetail(generic.DetailView):
    model = Pizza
    template_name = 'pizza/pizza_detail.html'
    context_object_name = 'pizza'
    def get_context_data(self, **kwargs):
        context = super(PizzaDetail, self).get_context_data(**kwargs)
        id = self.kwargs['pk']
        topping_qty = Topping.objects.filter(pizza=id).annotate(sum=Sum('qty'))
        return context

parlor_detail.html

{% extends "pizza/my_base.html" %}
{% block content %}
    <div>Parlor: {{ name }}</div>

    <div>Pizzas Made at Parlor</div>

    {% for pizza in pizzas.all %}
      <div>Pizza: {{ pizza.name }}</div>
      <div>Toppings: {{ pizza.topping_qty.sum }}</div>
    {% endfor %}

    <div> Total Qty of Toppings For Parlor: pizzas.topping_qty </div>
{% end block content %}
  • You have a few typos and basic mistakes that I'm sure you could pick up if you just went through it carefully. For example: `ParlorDetail` has `model = Pizza`, and you spell pizza wrong in `Topping.objects.filter(piza=id)`. The `topping_qty` queryset in `ParlorDetail` won't run, but even if it did it would not produce a measure topping quantity, because it's querying the Pizza model, not the Topping model. In both views, you are not actually adding anything to the context dictionary. – ChidG Mar 03 '20 at 05:57
  • I corrected the typos and misspellings. – Matt Revenaugh Mar 03 '20 at 11:59
  • I have found I can add a function to the child-record model like this that then en-totals the grand-children records `def total_toppings(self): packageSet = Topping.objects.filter(pizza=self.id) return packageSet.aggregate(sum=Sum('qty'))['sum'] ` But is this kosher? – Matt Revenaugh Mar 03 '20 at 12:08
  • Yes, this is fine, although you could be more concise: (on `Pizza` model) `return self.topping_set.aggregate(sum=Sum('qty'))['sum']` – ChidG Mar 04 '20 at 02:29

0 Answers0