Django ListView如何为每个培训项查询对应学员人数并添加到上下文
实现方案
最优方案:使用ORM注解聚合查询(仅1次数据库查询,无N+1性能问题)
这是效率最高的实现方式,直接在查询培训列表的同时,给每个培训对象新增学员人数属性,不需要额外循环查询:
首先修改你的视图代码,引入Count聚合函数,重写get_queryset方法:
from django.db.models import Count class TrainingsView(ListView): model = NewHireTraining template_name = 'nht/trainings.html' context_object_name = 'trainings' def get_queryset(self): # 给每个培训项注解关联的学员人数,注解后每个培训对象会新增trainee_count属性 return super().get_queryset().annotate( trainee_count=Count('trainee') )
注:如果你的Trainee模型中
new_hire_training外键没有自定义related_name,默认反向关联名是trainee_set,把上面Count的参数改成'trainee_set'即可。如果要让代码更易读,建议给外键加上related_name配置:# 修改Trainee模型的外键定义 new_hire_training = models.ForeignKey(NewHireTraining, on_delete=models.CASCADE, related_name='trainees')改完后Count参数就可以写成
'trainees',语义更清晰。
模板中使用方法
直接遍历培训列表即可调用注解生成的人数属性:
{% for training in trainings %} <div> <h3>培训项目:{{ training.program }}-{{ training.project }}</h3> <p>开班时间:{{ training.start_date }}</p> <p>当前学员人数:{{ training.trainee_count }}</p> </div> {% endfor %}
可选进阶:过滤统计规则
如果需要只统计在职(未离职is_term=False)的学员,可以给Count加上过滤条件:
from django.db.models import Count, Q def get_queryset(self): return super().get_queryset().annotate( # 仅统计未离职的学员人数 trainee_count=Count('trainees', filter=Q(trainees__is_term=False)) )
内容的提问来源于stack exchange,提问作者ivan corniel
相关产品推荐
相关产品推荐

