You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django QuerySet中计算发票总税费与总金额

计算发票总税费与总金额的QuerySet实现

先给出符合常见业务场景的模型字段假设(如果你的实际模型字段不同,对应调整即可):

# 模型示例
class PriceMaster(models.Model):
    product_name = models.CharField(max_length=100)
    tax_rate = models.DecimalField(max_digits=5, decimal_places=2)  # 存储百分比数值,如13表示13%

class Invoice(models.Model):
    invoice_no = models.CharField(max_length=50, unique=True)
    created_date = models.DateTimeField(auto_now_add=True)

class InvoiceItem(models.Model):
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='items')
    price_master = models.ForeignKey(PriceMaster, on_delete=models.CASCADE)
    quantity = models.IntegerField()
    unit_price = models.DecimalField(max_digits=10, decimal_places=2)

1. 单张发票的税费与总金额计算

如果需要单独获取某张发票的汇总数据:

from django.db.models import F, Sum, DecimalField

# 定位目标发票
invoice = Invoice.objects.get(invoice_no='INV-001')

# 计算该发票的总税费和总金额
invoice_summary = invoice.items.aggregate(
    total_tax=Sum(
        F('quantity') * F('unit_price') * (F('price_master__tax_rate') / 100),
        output_field=DecimalField(max_digits=12, decimal_places=2)
    ),
    total_amount=Sum(
        F('quantity') * F('unit_price') * (1 + F('price_master__tax_rate') / 100),
        output_field=DecimalField(max_digits=12, decimal_places=2)
    )
)
# 返回结果示例:{'total_tax': Decimal('130.00'), 'total_amount': Decimal('1130.00')}

2. 批量获取所有发票的汇总数据(带序号)

如果要在页面展示所有发票的序号、发票编号、总税费、总金额,用annotate关联发票与对应项目的汇总值:

from django.db.models import F, Sum, DecimalField, RowNum

# 生成带序号的发票汇总列表
invoice_list = Invoice.objects.annotate(
    total_tax=Sum(
        F('items__quantity') * F('items__unit_price') * (F('items__price_master__tax_rate') / 100),
        output_field=DecimalField(max_digits=12, decimal_places=2)
    ),
    total_amount=Sum(
        F('items__quantity') * F('items__unit_price') * (1 + F('items__price_master__tax_rate') / 100),
        output_field=DecimalField(max_digits=12, decimal_places=2)
    ),
    # Django 3.2+支持用RowNum生成数据库层面的序号
    serial_no=RowNum()
).values('serial_no', 'invoice_no', 'total_tax', 'total_amount').order_by('invoice_no')

3. 视图传递数据到模板

在视图中把查询结果传给前端模板:

def invoice_summary_view(request):
    invoice_list = Invoice.objects.annotate(
        total_tax=Sum(
            F('items__quantity') * F('items__unit_price') * (F('items__price_master__tax_rate') / 100),
            output_field=DecimalField(max_digits=12, decimal_places=2)
        ),
        total_amount=Sum(
            F('items__quantity') * F('items__unit_price') * (1 + F('items__price_master__tax_rate') / 100),
            output_field=DecimalField(max_digits=12, decimal_places=2)
        ),
        serial_no=RowNum()
    ).values('serial_no', 'invoice_no', 'total_tax', 'total_amount').order_by('invoice_no')
    
    return render(request, 'invoice_summary.html', {'invoice_list': invoice_list})

4. 模板页面展示

在模板中循环渲染数据:

<table>
    <thead>
        <tr>
            <th>序号</th>
            <th>发票编号</th>
            <th>总税费</th>
            <th>总金额</th>
        </tr>
    </thead>
    <tbody>
        {% for invoice in invoice_list %}
        <tr>
            <td>{{ invoice.serial_no }}</td>
            <td>{{ invoice.invoice_no }}</td>
            <td>{{ invoice.total_tax|floatformat:2 }}</td>
            <td>{{ invoice.total_amount|floatformat:2 }}</td>
        </tr>
        {% empty %}
        <tr>
            <td colspan="4">暂无发票数据</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

注意事项

  • 如果PriceMaster中的税率是小数形式(如0.13表示13%),直接移除计算中的/100部分即可。
  • 确保DecimalField的精度设置足够,避免计算时出现溢出问题。
  • 若使用低于Django 3.2的版本,序号可在模板中用{{ forloop.counter }}代替RowNum。

内容的提问来源于stack exchange,提问作者shyam rathod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 05:13:42