【问题标题】:Django - Cannot filter a query once a slice has been takenDjango - 获取切片后无法过滤查询
【发布时间】:2021-08-17 04:01:39
【问题描述】:

我正在使用基于类的视图,当我尝试将“paginate_by = 6”与“def get_context_data(self, **kwargs):”一起使用时,我收到以下错误:

AssertionError at /

Cannot filter a query once a slice has been taken.

Request Method:     GET
Request URL:    http://127.0.0.1:8000/
Django Version:     3.2
Exception Type:     AssertionError
Exception Value:    

Cannot filter a query once a slice has been taken.

Exception Location:     C:\Users\xxxx\xxxx\xxxx\env\lib\site-packages\django\db\models\query.py, line 953, in _filter_or_exclude
Python Executable:  C:\Users\xxxx\xxxx\xxxx\env\Scripts\python.exe
Python Version:     3.9.1
Python Path:    

['C:\\Users\\xxxx\\xxxx\\xxxx',
 'C:\\Program Files\\Python39\\python39.zip',
 'C:\\Program Files\\Python39\\DLLs',
 'C:\\Program Files\\Python39\\lib',
 'C:\\Program Files\\Python39',
 'C:\\Users\\xxxx\\xxxx\\xxxx\\env',
 'C:\\Users\\xxxx\\xxxx\\xxxx\\env\\lib\\site-packages']

Server time:    Sat, 29 May 2021 00:11:20 +0000

我正在尝试对过滤器结果进行分页,就像没有应用过滤器一样,它应该对所有任务进行分页。

我只找到了不使用分页器功能的解决方案。我想知道是否可以使用基于类的视图以及如何处理,我对此有点迷茫。

我的意见.py:

class TaskList(LoginRequiredMixin, ListView):
    model = Task
    context_object_name = "tasks"
    template_name = "todo/tasks.html"
    paginate_by = 6

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["tasks"] = context["tasks"].filter(user=self.request.user)
        context["count"] = context["tasks"].filter(complete=False).count()
        context["projects"] = Project.objects.all()

        search_input = self.request.GET.get("search") or ""
        project_input = self.request.GET.get("project") or ""
        complete_input = self.request.GET.get("complete") or ""

        if search_input:
            context["tasks"] = context["tasks"].filter(title__icontains=search_input)
            context["count"] = context["tasks"].filter(complete=False).count()

        context["search_input"] = search_input

        if project_input:
            context["project_selected"] = project_input
            context["tasks"] = context["tasks"].filter(
                project__name__icontains=project_input
            )
            context["count"] = context["tasks"].filter(complete=False).count()

        if complete_input == "all":
            context["complete_selected"] = complete_input
            context["tasks"] = context["tasks"].filter(user=self.request.user)
            context["count"] = context["tasks"].filter(complete=False).count()
        else:
            if complete_input:
                context["complete_selected"] = complete_input
                context["tasks"] = context["tasks"].filter(
                    user=self.request.user, complete=True
                )
                context["count"] = context["tasks"].filter(complete=True).count()
            else:
                context["complete_selected"] = ""
                context["tasks"] = context["tasks"].filter(
                    user=self.request.user, complete=False
                )

        return context

我的模型.py:

class Task(models.Model):
    project = models.ForeignKey(Project, on_delete=CASCADE)
    user = models.ForeignKey(User, on_delete=SET_NULL, null=True, blank=True)
    title = models.CharField(max_length=255)
    description = RichTextField(null=True, blank=True)
    complete = models.BooleanField(default=False)
    time = models.TimeField(default=datetime.time(00, 00))
    date = models.DateField(default=datetime.date.today)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ["complete", "-date", "title"]

如果需要,我可以添加更多信息

【问题讨论】:

    标签: python django django-views


    【解决方案1】:

    创建上下文['tasks'] 的深层副本并在对象副本而不是主对象上应用切片

    【讨论】:

    • 你能举个例子说明应该怎么做吗?
    【解决方案2】:

    我做了一个解决方法,我将分页应用到上下文 [“tasks”],然后我复制 url 以维护每个页面上的过滤。

    views.py:

    class TaskList(LoginRequiredMixin, ListView):
    model = Task
    context_object_name = "tasks"
    template_name = "myapp/list.html"
    
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["tasks"] = context["tasks"].filter(user=self.request.user)
        context["count"] = context["tasks"].filter(complete=False).count()
        context["projects"] = Project.objects.all()
    
        search_input = self.request.GET.get("search") or ""
        project_input = self.request.GET.get("project") or ""
        complete_input = self.request.GET.get("complete") or ""
    
        if search_input:
            context["tasks"] = context["tasks"].filter(title__icontains=search_input)
            context["count"] = context["tasks"].filter(complete=False).count()
    
        context["search_input"] = search_input
    
        if project_input:
            context["project_selected"] = project_input
            context["tasks"] = context["tasks"].filter(
                project__name__icontains=project_input
            )
            context["count"] = context["tasks"].filter(complete=False).count()
    
        if complete_input == "all":
            context["complete_selected"] = complete_input
            context["tasks"] = context["tasks"].filter(user=self.request.user)
            context["count"] = context["tasks"].filter(complete=False).count()
        else:
            if complete_input:
                context["complete_selected"] = complete_input
                context["tasks"] = context["tasks"].filter(
                    user=self.request.user, complete=True
                )
                context["count"] = context["tasks"].filter(complete=True).count()
            else:
                context["complete_selected"] = ""
                context["tasks"] = context["tasks"].filter(
                    user=self.request.user, complete=False
                )
    
        # Pagination
        paginated_tasks = Paginator(context["tasks"], 6)
        page_number = self.request.GET.get("page")
        task_page_obj = paginated_tasks.get_page(page_number)
    
        context["task_page_obj"] = task_page_obj
    
        get_copy = self.request.GET.copy()
        if get_copy.get("page"):
            get_copy.pop("page")
        context["get_copy"] = get_copy
    
        return context
    

    list.html:

    ...
    {% for task in task_page_obj %}
    {% empty %}
    <p>No tasks to show...</p>
    {% endfor %}
    <div class="pagination">
    <span class="step-links">
        {% if task_page_obj.has_previous %}
            <a href="?page=1&{{ get_copy.urlencode }}">&laquo; first</a>
            <a href="?page={{ task_page_obj.previous_page_number }}&{{ get_copy.urlencode }}">previous</a>
        {% endif %}
    
        <span class="current">
            Page {{ task_page_obj.number }} of {{ task_page_obj.paginator.num_pages }}.
        </span>
    
        {% if task_page_obj.has_next %}
            <a href="?page={{ task_page_obj.next_page_number }}&{{ get_copy.urlencode }}">next</a>
            <a href="?page={{ task_page_obj.paginator.num_pages }}&{{ get_copy.urlencode }}">last &raquo;</a>
        {% endif %}
    </span>
    </div>
    

    【讨论】:

      【解决方案3】:

      在这种情况下,您应该在下面的函数中过滤您的查询集,它将覆盖默认的:

      def get_queryset(self): return '&lt;your query&gt;'

      发生错误是因为您在过滤后尝试更改未评估的查询集。 现在您可以使用paginate_by = n,您应该不会收到任何错误。

      【讨论】:

        猜你喜欢
        • 2021-03-05
        • 1970-01-01
        • 1970-01-01
        • 2012-09-11
        • 1970-01-01
        • 1970-01-01
        • 2011-05-16
        • 2013-07-20
        • 2015-10-26
        相关资源
        最近更新 更多