Django CBV ListView中外键关联数据统计的实现疑问
解决Django CBV(ListView)中展示Periode关联统计数据的问题
首先得纠正下你模型里的小问题:EmployeeSalary中的related_name设置得有点混淆,比如related_name='employee'和related_name='periode',既会和模型名称冲突,也不符合逻辑(一个Periode应该对应多条薪资记录),先把这个修正,后续操作才更清晰:
class EmployeeSalary(models.Model): employee = models.ForeignKey(Employee, related_name='salaries', on_delete=models.CASCADE) periode = models.ForeignKey(Periode, related_name='salary_records', on_delete=models.CASCADE)
接下来,我们可以通过**Django的聚合注解(annotate)**在ListView中直接给每个Periode对象添加统计字段,同时把总员工数传入模板,轻松计算出无薪资数据的员工数。
步骤1:修改ListView的逻辑
重写get_queryset和get_context_data方法,提前计算好需要的统计数据:
from django.views.generic import ListView from django.db.models import Count, Value, F from django.db.models.fields import IntegerField from .models import Periode, Employee class PeriodeListView(ListView): model = Periode template_name = 'your_template.html' # 替换成你的模板路径 context_object_name = 'periodes' def get_queryset(self): # 获取全局总员工数,用于计算无薪资员工数 total_employees = Employee.objects.count() # 给每个Periode添加统计注解 queryset = super().get_queryset().annotate( # 该周期的薪资数据总数 salary_records_count=Count('salary_records'), # 该周期有薪资记录的员工数(去重,避免一个员工多条记录重复计数) paid_employee_count=Count('salary_records__employee', distinct=True) ).annotate( # 直接计算无薪资数据的员工数:总员工数 - 有薪资的员工数 unpaid_employee_count=Value(total_employees, output_field=IntegerField()) - F('paid_employee_count') ) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 把总员工数传入模板,方便展示 context['total_employees'] = Employee.objects.count() return context
步骤2:在模板中展示数据
现在模板里可以直接调用这些预计算好的字段,不需要复杂逻辑:
<table border="1" cellpadding="8"> <thead> <tr> <th>周期</th> <th>总员工数</th> <th>薪资数据数</th> <th>无薪资数据员工数</th> </tr> </thead> <tbody> {% for periode in periodes %} <tr> <td>{{ periode.start_date|date:"Y-m-d" }} 至 {{ periode.end_date|date:"Y-m-d" }}</td> <td>{{ total_employees }}</td> <td>{{ periode.salary_records_count }}</td> <td>{{ periode.unpaid_employee_count }}</td> </tr> {% empty %} <tr> <td colspan="4">暂无周期数据</td> </tr> {% endfor %} </tbody> </table>
为什么你之前的尝试没成功?
你用的periode.periode.employee.count有两个核心问题:
related_name设置错误:你把EmployeeSalary的periode字段的related_name设为periode,导致调用periode.periode时拿到的是该周期关联的薪资记录集合,而非员工数据;- 未去重统计:就算你拿到了薪资记录里的员工,直接
count会把重复的员工(如果一个员工有多个薪资记录)重复计数,必须用distinct=True来统计唯一的员工数。
内容的提问来源于stack exchange,提问作者Dicky Raambo
相关产品推荐
相关产品推荐

