Django中如何在渲染前过滤模型Queryset并向utils传递用户信息
你重写的get_queryset不生效的核心原因是:utils.py中的Calendar类的formatmonth方法直接硬编码查询了Class模型,完全没有使用ListView过滤后的数据集,所以不管你怎么修改get_queryset,日历渲染时都会走独立的全量查询逻辑。
解决方案
实现思路
将数据过滤逻辑全部移到视图层处理,过滤完成后再把结果传给Calendar类做渲染,既可以直接调用self.request.user做身份过滤,也符合Django分层设计的规范。
步骤1:修改utils.py中的Calendar类
删除formatmonth方法中硬编码的查询逻辑,改为接收外部传入的events参数:
# utils.py class Calendar(HTMLCalendar): # 保留其他原有方法不变 def formatmonth(self, events, withyear=True): # 删除原来的events = Class.objects.filter(...)那行代码 cal = f'<table border="0" cellpadding="0" cellspacing="0" class="calendar">\n' cal += f'{self.formatmonthname(self.year, self.month, withyear=withyear)}\n' cal += f'{self.formatweekheader()}\n' for week in self.monthdays2calendar(self.year, self.month): cal += f'{self.formatweek(week, events)}\n' return cal
步骤2:修改视图逻辑,完成身份过滤后传参
在视图的get_queryset中完成用户身份、月份的过滤,再把结果传给formatmonth方法:
# views.py class CalendarView(LoginRequiredMixin, generic.ListView): model = Class template_name = 'leads/calendar.html' def get_queryset(self): base_queryset = super().get_queryset() # 获取当前登录用户 current_user = self.request.user # 按用户身份过滤,示例逻辑可自行修改 if current_user.is_student: base_queryset = base_queryset.filter(student=current_user) elif current_user.is_teacher: base_queryset = base_queryset.filter(teacher=current_user) # 按当前查询的月份过滤 d = get_date(self.request.GET.get('month', None)) base_queryset = base_queryset.filter( date__year=d.year, date__month=d.month ).exclude(student=None) return base_queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) d = get_date(self.request.GET.get('month', None)) cal = Calendar(d.year, d.month) # 把过滤好的课程数据传给日历渲染方法 html_cal = cal.formatmonth(events=self.get_queryset(), withyear=True) context['calendar'] = mark_safe(html_cal) context['prev_month'] = prev_month(d) context['next_month'] = next_month(d) return context
补充说明
模板代码不需要做任何修改,原有逻辑可以直接复用。如果后续需要调整过滤规则,只需要修改视图层的get_queryset方法即可,不需要改动工具类的渲染逻辑。
内容的提问来源于stack exchange,提问作者coderDcoder
相关产品推荐
相关产品推荐

