[Django]-Display multiple related Django models in a table design problem

6πŸ‘

βœ…

If you have that date model so you can fetch all bs then group them by a and calculate total amount. Code may look like this:

View:

from django.utils.itercompat import groupby

def view(request):
   bs = B.objects.all().annotate(sum_of_c_val=Sum('c.val'))\
                       .select_related('a')
   b_by_a = [
            {
               'grouper': key,
               'list': list(val),
               'total': sum([b.sum_of_c_val for b in val])
            }
            for key, val in
            groupby(bs, lambda b: b.a)
   ]

   return render_to_response('tmpl.html', {'b_by_a': b_by_a})

And template:

{% for b_group in b_by_a %}
  {% for b in b_group.list %}
    <tr>
        <td>{{b_group.grouper.name}}</td>
        <td>{{b.name}}</td>
        <td>{{b.sum_of_c_val}}</td>
    </tr>
  {% endfor %}
  <tr>
      <td>{{b_group.grouper.name}}</td>
      <td>Total</td>
      <td>{{b_group.total}}</td>
  </tr>
{% endfor %}

EDIT:

For compatible with Django 1.0 you have to replace annotate call with extra select or in-python amount calculation.

  1. With subquery:

    bs = B.objects.all().extra(
        select={
          'sum_of_c_val': 'SELECT SUM(app_c.val) FROM app_c WHERE app_c.b_id=app_b.id'
        }).select_related('a')
    #...
    

    Where app – application name

  2. This in-python calculation:

     bs = B.objects.all().select_related('a')
     for b in bs:
         b.sum_of_c_val = sum(map(int, b.c.all().values_list("val", flat=True)))
     #...
    

    But it produces N additional queries (where N = len(bs))

πŸ‘€Alex Koshelev

1πŸ‘

Disclaimer: I’m a Django beginner myself, but if I’ve understood its basic concepts right, then:

Given that the view you want is – as you say – just a view of the underlying data, then you should do the sorting and grouping in the view module. I don’t think you should mess with the model (which is just the data), nor with the template (which is just a layout of the view).

Leave a comment