django / python中计费层次结构中子节点的总和

时间:2018-08-22 17:33:20

标签: python django recursion

如何在Python / Django的会计层次结构中为多个级别的父节点创建一个子节点总和?

我目前有一个显示单个帐户总和的应用程序,但是这些值未添加到父级帐户中。

该应用具有以下型号:

from django.db import models

class accounts(models.Model):
    account_nr = models.IntegerField(null=True)
    account_name = models.CharField(max_length=100)
    account_parent_nr = models.IntegerField(null=True)

class transactions(models.Model):
    transaction_id = models.CharField(max_length=100)
    account_ID = models.ForeignKey(accounts, on_delete=models.CASCADE)
    debit_value = models.DecimalField(max_digits=10, decimal_places=2)
    credit_value = models.DecimalField(max_digits=10, decimal_places=2)

一些示例数据是:

account_nr    account_name     account_parent_nr
1000          current assets   null
1001          cash             1000
1002          bank             1000
1010          debtors          1000
1011          debtor 1         1010
1012          debtor 2         1010
3000          stock            null
3010          category 1       3000
3011          product a        3010
3012          product b        3010     
...
0010          equity           null
0011          owner x          0010
0012          owner y          0010

交易的样本数据将是:

transaction_id    account_id    debit_value    credit_value
1                 1001          100            0
1                 0011          0              100
2                 1002          100            0
2                 0011          0              100
3                 1011          100            0
3                 0011          0              100
4                 1012          100            0
4                 0011          0              100
5                 3011          50             0
5                 3012          50             0
5                 0012          0              100

使用以下视图:

from django.shortcuts import render
from django.db.models import Sum

from .models import accounts, transactions

def home(request):
    account_query = accounts.objects.all() \
    .annotate(Sum('transactions__debit_value')) \
    .annotate(Sum('transactions__credit_value')) \
    .order_by('account_nr')
    args = {'account_queryx': account_query}
    return render(request, 'home.html', args)

以及以下模板:

{% extends "base.html" %}

{% block content %}
  <table>
    <tr>
      <th>Account</th>
      <th>Omschrijving</th> 
      <th>Debit</th>
      <th>Credit</th>
    </tr>
    {% for account_query in account_queryx %}
    <tr>
      <td>{{ account_query.account_nr }}</td>
      <td>{{ account_query.account_name }}</td>
      <td>{{ account_query.transactions__debit_value__sum}}</td>
      <td>{{ account_query.transactions__credit_value__sum }}</td>
     </tr>
    {% endfor %}
    </table>
</div>
{% endblock %}

我现在得到这样的结果:

acount_id    account_name    debit    credit
1000         current assets  null     null
1001         cash            100      0
1002         bank            100      0
1010         debtors         null     null
1011         debtor 1        100      0
1012         debtor 2        100      0
3000         stock           null     null
3010         category 1      null     null
3011         product a       50       0
3012         product b       50       0       
...
0010         equity          null     null
0011         owner x         0        400
0012         owner y         0        100

我最后要说的是,现在显示为null的值是子节点的总和。我更喜欢在自己的views.py中实现一个解决方案。

我一直在寻找可以帮助我解决这一问题的理论。我发现递归求和可能会有所帮助,但是我很难将其纳入工作代码中。我不明白应该使用哪种算法基于帐号/父母/子女关系创建总和。

1 个答案:

答案 0 :(得分:0)

我认为您正在构想一种需要更复杂的数据模型的数据模型,该模型可以分辨哪些特定子帐户是父帐户的子帐户,并且需要相应地更复杂的查询才能在您访问数据库时对这些子帐户进行小计。

如果缺少此功能,我建议您基本上像现在一样获取原始数据,然后对其进行迭代以构建可用于演示的数据集,然后在小计中在视图中进行格式化...

from django.shortcuts import render
from django.db.models import Sum

from .models import accounts, transactions

def home(request):

    # Get the raw account balances

    account_query_raw = accounts.objects.all() \
    .annotate(Sum('transactions__debit_value')) \
    .annotate(Sum('transactions__credit_value')) \
    .order_by('account_nr')

    # Build the updated dataset with account sums

    account_query = [ ]
    cur_parent_index = None

    for account in account_query_raw:

        account_query.append( account )

        if not account_query.transactions__debit_value__sum:

            # new parent account...
            # set null sums in parent records to zero

            current_parent_index = len( account_query ) -1
            parent = account_query[ cur_parent_index ]

            parent.transactions__debit_value = 0
            parent.transactions__credit_value = 0

        elif current_parent_index:

            # if we have a current parent account,
            # include this account in the parent's sum

            parent = account_query[ cur_parent_index ]

            parent.transactions__debit_value__sum += \
                account.transactions__debit_value__sum

            parent.transactions__credit_value__sum += \
                account.transactions__credit_value__sum

    args = {'account_queryx': account_query}

    return render(request, 'home.html', args)

通常有一种趋势,认为您想在数据库上进行所有此类数据操作,但是如果您必须将所有结果记录从数据库中拉回以进行渲染,那么实际上并没有太多直接在Python中将它们直接操纵成您所需的性能问题。