Mapping multiple related Django models in a table design task

I am struggling with django app design. Given the following models:

class A(models.Model):
    name = models.CharField(max_length=255)

class B(models.Model):
    name = models.CharField(max_length=255)
    a = models.ForeignKey(A)

class C(models.Model):
    val = models.IntegerField()
    b = models.ForeignKey(B)

I would like the view / template to display an HTML table that shows all objects A in the first column, all B objects (grouped by A) that A refer to in the second column, and the sum of all val objects from C in the last column, which apply to each B. All this with a sum for each object A. The following example shows what I'm looking for:

A1.name | B1.name [where FK to A1] | sum (C.val) [where FK to B1]
A1.name | B2.name [where FK to A1] | sum (C.val) [where FK to B2]
A1.name | Total | sum (C.val) [where FK to Bx (all B that have FK to A1]
A2.name | B3.name [where FK to A2] | sum (C.val) [where FK to B3]
A2.name | Total | sum (C.val) [where FK to Bx (all B that have FK to A2]

Can someone give me advice on how to develop such a problem (unfortunately, my code often ends up in quite a mess)?

Should I extend model classes using appropriate methods? Does the user query do all the tabular data in the view? Just get all the objects through the managers and do most of the things in the template?

Thanks for every reply.

Hello,

Bows.

+3
source share
2 answers

If you have this date model, you can get everything band then group them by aand calculate the total amount. The code might 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 the 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:

Django 1.0 annotate extra in-python.

  • :

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

    app -

  • python:

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

    N ( N = len(bs))

+5

: Django, , :

, , , - , , , . , ( ), ( ).

+1

Source: https://habr.com/ru/post/1703023/


All Articles