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

Django中如何从ForeignKey关联模型取值并求和?

解决Django一对多关系中聚合求和的问题

首先,咱们先理清问题所在:你遇到的报错是因为一个EmpLoan对应多个EmpInstallment,但你在模板里直接用emploan.installment.nominal,相当于尝试从一对多关系中获取单个对象,而实际返回了多个,所以触发了错误。另外,你的关联字段的related_name是empinstallment,不是installment,这也是导致访问失败的原因之一。

下面给你两种解决方案,优先推荐第一种(性能更优):

方法一:在视图中用数据库聚合提前计算总和

这种方法直接在数据库层面完成求和,避免模板中多次查询数据库,性能更好。

修改你的EmpLoanListView,使用Sum聚合函数给每个EmpLoan对象添加一个total_installment字段,存储对应分期的总金额:

from django.db.models import Sum
from django.views.generic import ListView
import models  # 确保导入你的模型

class EmpLoanListView(ListView):
    context_object_name = 'emploans'
    model = models.EmpLoan

    def get_queryset(self):
        # 给每个贷款对象添加总分期金额的聚合字段
        return super().get_queryset().annotate(
            total_installment=Sum('empinstallment__nominal')
        )

    def get_context_data(self, **kwargs):
        context = super(EmpLoanListView, self).get_context_data(**kwargs)
        context['form'] = EmpLoanForm()
        return context

然后在模板中直接使用这个预计算好的字段:

{% for emploan in emploans %}
<tr>
    <td>{{ emploan.employee.name }}</td>
    <td>{{ emploan.nominal|intcomma }},-</td>
    <td>{{ emploan.total_installment|default:"0"|intcomma }},-</td>
</tr>
{% endfor %}

这里加了|default:"0"是为了处理没有分期的贷款,避免显示空值。

方法二:在模板中遍历求和(不推荐,性能较差)

如果暂时不想修改视图,也可以在模板中遍历所有分期并累加,但这种方法会对每个贷款发起额外的数据库查询,数据量大时性能会受影响:

{% for emploan in emploans %}
<tr>
    <td>{{ emploan.employee.name }}</td>
    <td>{{ emploan.nominal|intcomma }},-</td>
    <td>
        {% with total=0 %}
            {% for installment in emploan.empinstallment.all %}
                {% total = total + installment.nominal %}
            {% endfor %}
            {{ total|intcomma }},-
        {% endwith %}
    </td>
</tr>
{% endfor %}

额外建议:完善模型的外键设置

你的EmpInstallment模型中的loan外键没有设置on_delete参数,这在Django中是必填项,建议补充上,比如使用CASCADE(删除贷款时自动删除对应的分期):

class EmpInstallment(models.Model):
    nominal = models.DecimalField(max_digits=10, decimal_places=0)
    loan = models.ForeignKey(EmpLoan, related_name='empinstallment', on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now=True)

内容的提问来源于stack exchange,提问作者Dicky Raambo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:06:09