Django ListView如何向模板传递User实例的动态条件属性today_note
实现方案
方案1:最小改动适配现有逻辑
你当前代码的问题是处理完添加了today_note属性的员工列表没有绑定到context上下文对象中,直接在循环处理完成后给context的employees键赋值即可,修改后的视图代码如下:
from django.db.models import Q from datetime import date class AllEmployeesList(ListView): template_name = "users/all_employees.html" model = User context_object_name = 'employees' def get_context_data(self, **kwargs): context = super(AllEmployeesList, self).get_context_data(**kwargs) all_employees = User.objects.order_by('first_name', 'last_name').all() today = date.today() for employee in all_employees: # 这里用.exists()替代len(xxx.all()),查询效率更高 today_sick = Sickleave.objects.filter( Q(start_date__lte=today) & Q(end_date__gte= today) & Q(employee__id=employee.id) ).exists() employee.today_note = "C" if today_sick else "✓" # 把处理后的员工列表赋值给context,替换默认生成的员工列表 context['employees'] = all_employees return context
模板调用方式和你之前的逻辑一致,直接遍历即可:
{% for employee in employees %} {{ employee.today_note }} {% endfor %}
方案2:性能优化版(解决N+1查询问题)
上述方案如果员工数量较多会产生N+1次数据库查询(1次查所有员工,每个员工单独查1次病假记录),可以用Django的annotate+Exists一次性完成状态标注,全程只需要2次数据库查询:
from django.db.models import Exists, OuterRef, Value, Case, When, CharField from datetime import date class AllEmployeesList(ListView): template_name = "users/all_employees.html" model = User context_object_name = 'employees' def get_queryset(self): today = date.today() # 子查询:判断当前员工是否在今日病假范围内 sick_leave = Sickleave.objects.filter( employee=OuterRef('pk'), start_date__lte=today, end_date__gte=today ) # 给查询集直接添加today_note注解 return super().get_queryset().annotate( today_sick=Exists(sick_leave) ).annotate( today_note=Case( When(today_sick=True, then=Value("C")), default=Value("✓"), output_field=CharField() ) ).order_by('first_name', 'last_name')
这个方案不需要额外修改get_context_data,注解生成的today_note可以直接在模板中调用,使用方式和方案1完全一致。
内容的提问来源于stack exchange,提问作者treflina
相关产品推荐
相关产品推荐

