Django - 如何显示数据矩阵,每行和每列的末尾都有总和

时间:2015-12-27 19:18:09

标签: python django matrix

好的 - 所以我实际上要显示的是使用基金会计的公司的合并资产负债表。

但为了简单起见,我将使用类比。

假设有一群人要去公路旅行。领导对每个人说:“给我一份你希望我为旅行购买的所有杂货的清单”。所有想要把他的名单交给他的人。从该列表中,领导者将一个主列表放在一起,从中可以购买杂货。

有两个主要的未知数:

  1. 这次旅行有多少人,因此提供一份清单
  2. 每个列表中的项目(和数量)
  3. 例如,假设有两个人提供列表,它们可能如下所示:

    人A

    • 4个苹果
    • 6香蕉
    • 1盒破解者

    人B

    • 2香蕉
    • 4 Oranges
    • 1西瓜

    从这两个列表中,领导者必须生成如下列表:

          Person      A  B  Total
                    ------------
    Apples            4  0   4
    Bananas           6  2   8
    Oranges           0  4   4
    Watermelon        0  1   1
    ----------------------------
        **Fruit**    10  7  17
    
    Box of Crackers   1  0   1
    ----------------------------
        **Other**     1  0   1
    

    您可以看到最终列表是一个矩阵,其中包含每个项目(行)的总计,但随后会为每个主要类别(水果/其他)再次合计。使用两个未知数(人/项),此矩阵可以包含任意数量的人(列)和任意数量的项(行)。此外,该列表分为“水果”和“其他”,总计在这些组中。

    我需要弄清楚如何显示这种数据(但是用于记帐)。我已经尝试过使用列表,我将Person A的所有项目放入一个列表,将Person B的所有项目放入另一个列表,然后迭代我的Django模板上的列表,但这并不是很好。

    我可以想象有多种方法可以解决这个问题,我只是不确定最有效的方法是什么,知道每个主列表可能有很多“人”和许多“项目”。

    同样,这实际上是为使用基金会计显示公司的合并资产负债表。因此,“人民”实际上是基金,“杂货项目”实际上是每个基金内的账户。并非每个基金都拥有与其他基金相同的账户。

    修改

    为清楚起见,我这样建模:

    model Person
      field: persons_name
    
    model ItemType:
      field: i_types #Things like "Fruit", "Veggies", "Canned Goods", etc.
    
    model Item
      field: item_name
      FK: ItemType
    
    
    model Selection
      FK: Person
      FK: Item
      field: qty
    

    编辑2 为我的模型添加了更多字段

2 个答案:

答案 0 :(得分:3)

您应该避免在模板中执行除演示之外的任何操作。我的建议是在视图中构建一些方便的数据结构,然后在模板中迭代它们:

  • list“人物”(创建表格标题)
  • 一个dictionary项,其中项是键(您可以使用项的字符串表示来使事情更简单),并且值是一个有序的项列表,其顺序与列表中的顺序相同订购前一点;您也可以将总数附加到此列表中。

这样可以更轻松地处理模板中的内容,您可以使用以下内容:

<table>
    <thead>
        <tr>
            <td>Item name</td>
            {% for person in person_list %}
                <td>{{ person.name }}</td>
            {% endfor %}
            <td>Total</td>
        </tr>
    </thead>
    <tbody>
        {% for item, item_list in item_dict.items %}
            <tr>
                <td>{{ item }}</td>
                {% for i in item_list %}
                    <td>{{ i }}</td>
                {% endfor %}
            </tr>
        {% endfor %}
    <tbody>
</table>

为了整合您的类别,dictionary结构可以进一步嵌套在具有数据(上面的词典)的类别dictionary中,也可以嵌套在总计列表中。

我建议的最重要的一点是,您应该在视图中构建所有结构,以便在模板中轻松显示它们,而不是相反 < / p>

答案 1 :(得分:0)

我根据你的模特制作了working example。以下是摘录和解释。

这就是您的观点:

from django.shortcuts import render
from .models import *

def index(request):
  all_selections = Selection.objects.all()
  all_people = set([selection.person for selection in all_selections])
  blank_person_counts = {person: 0 for person in all_people}
  all_categories = set([selection.item.category for selection in all_selections])

  categories = []

  for category in all_categories:
    selections = [s for s in all_selections if s.item.category == category]

    total_by_person = blank_person_counts.copy()

    unique_item_details = set([s.item for s in selections])

    items = [{'detail': item_details} for item_details in unique_item_details]
    total_by_item = {item['detail']: 0 for item in items}
    total_by_item_person = {item['detail']: blank_person_counts.copy() for item in items}

    for selection in selections:
      total_by_item_person[selection.item][selection.person] = selection.quantity
      total_by_item[selection.item] += selection.quantity
      total_by_person[selection.person] += selection.quantity

    for item in items:
      item['people_totals'] = [total_by_item_person[item['detail']][person] for person in all_people]
      item['total'] = total_by_item[item['detail']]

    people_totals = [total_by_person[person] for person in all_people]
    category_total = sum(people_totals)

    categories.append({
      'detail': category.name,
      'people_totals': people_totals,
      'total': category_total,
      'items': items
    })

  context = {'people': all_people, 'categories': categories}
  return render(request, 'matrix.html', context)

我从获得all_selections开始,因为我假设一个项目从未被选中,或者一个人从未选择过类别,所以不应该包含它们,因此选择是数据的核心。

从获得的选择中,我生成了一个人员列表(all_people)。在我们进入项目之前定义此项有助于我们确保每个项目都考虑到每个人。即使一个人没有选择一个项目,我们也会为该项目分配一个零数量。它还设置了人们显示为列的顺序,我们将在人们为每个项目和每个类别返回总计时使用相同的顺序。

由于数据按类别划分,我们会从选择列表中生成类别列表。然后,我们遍历每个类别,按该类别过滤选择,创建一个空白的平板,其中每个人选择的每个项目为零次。然后查看实际选择并使用数量更新计数。我们还维持每个类别的人均运行总数。最后,我们总结了每个人的运行总数,因为这将是该类别的总计。我们对每个类别重复相同的过程。

在模板中,基本上是循环这些数据并显示它:          

<h1>The Grocery Matrix</h1>

<table>
  <tr>
    <th></th>
    {% for person in people %}
      <th>{{ person }}</th>
    {% endfor %}
    <th>Total</th>
  </tr>

  {% for category in categories %}
    {% for item in category.items %}
    <tr>
      <td>{{ item.detail }}</td>
      {% for person_total_for_item in item.people_totals %}
        <td>{{ person_total_for_item }}</td>
      {% endfor %}
      <td>{{ item.total }}</td>
    </tr>
    {% endfor %}


    <tr>
      <td>{{ category.detail }}</td>
      {% for person_total_for_category in category.people_totals %}
        <td>{{ person_total_for_category }}</td>
      {% endfor %}
      <td>{{ category.total }}</td>
    </tr>

  {% endfor %}
</table>

</body>
</html>