首页 > 解决方案 > django/python 中会计层次结构中子节点的总和

问题描述

如何使用 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 中实现一个解决方案。

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

标签: pythondjangorecursion

解决方案


我认为您正在设想一些需要更复杂的数据模型的东西,该模型可以判断哪些特定的子账户是父账户的子账户,以及相应更复杂的查询来在您访问数据库时对这些子账户进行小计。

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

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 中将它们操作为您所需要的。


推荐阅读