Django CBV ListView使用paginate_by报错:object of type 'method' has no len()
嘿,我马上就发现你代码里的问题啦!这个TypeError的根源很清晰,咱们一步步来解决:
问题原因
你把ListView里的queryset写成了一个方法(def queryset(self)),但Django的ListView对这个属性的期望是:要么是一个类属性形式的QuerySet对象,要么你需要重写get_queryset()方法来动态返回查询集。
当你开启分页paginate_by = 5后,Django会尝试计算查询集的总长度来生成分页数据,但此时它拿到的是一个方法对象(而不是实际的Task查询集),自然就会抛出“object of type 'method' has no len()”的错误。
两种修复方案
方案一:重写get_queryset()方法(推荐)
这是处理动态查询集(比如依赖当前登录用户)的标准做法,修改后的代码如下:
from django.db.models import Q from django.views.generic import ListView from django.contrib.auth.mixins import LoginRequiredMixin import datetime class DashboardTaskAppView(LoginRequiredMixin, ListView): model = Task template_name = "task_app/task_dashboard.html" context_object_name = 'tasks' today = datetime.date.today() paginate_by = 5 def get_queryset(self): # 只有在实例方法里才能访问到self.request.user usr = self.request.user # 返回排序后的用户任务查询集 return Task.objects.filter(Q(responsable=usr)).order_by('-due_date')
方案二:直接设置类属性queryset(仅适用于不依赖请求的场景)
如果你的查询不需要依赖请求对象(比如不需要当前用户),可以直接把queryset设为类属性,但显然你的场景不适用这个,不过还是给你参考:
# 注意:这个示例里没法直接用request.user,所以仅作参考 class DashboardTaskAppView(LoginRequiredMixin, ListView): model = Task template_name = "task_app/task_dashboard.html" context_object_name = 'tasks' today = datetime.date.today() paginate_by = 5 queryset = Task.objects.all().order_by('-due_date')
额外优化小技巧
你原来代码里的ordering = ['-due_date']如果放在类属性里,ListView会自动应用这个排序规则,所以也可以把排序逻辑移到类属性,简化get_queryset():
class DashboardTaskAppView(LoginRequiredMixin, ListView): model = Task template_name = "task_app/task_dashboard.html" context_object_name = 'tasks' today = datetime.date.today() paginate_by = 5 ordering = ['-due_date'] # 类属性定义排序 def get_queryset(self): usr = self.request.user return Task.objects.filter(Q(responsable=usr))
这样修改后,分页功能就能正常工作啦!
内容的提问来源于stack exchange,提问作者Caio César P. Ricciuti
相关产品推荐
相关产品推荐

