Django - 在执行分页操作时出现了TypeError: object of type 'NoneType' has no len()错误

3
当我给列表视图添加分页时,出现了TypeError: object of type 'NoneType' has no len()的错误。这个错误发生在我点击“下一页”按钮进入第二页时。它应该有两个结果要显示。
我猜是因为当我点击“下一页(进入第二页)”时,search的值被清除或者queryset变成了空,然后返回了none错误信息: enter image description here 搜索表单: enter image description here book/views:
class SearchResultView(generic.ListView):
    template_name = 'book/search.html'
    model = Book
    context_object_name = 'book_list'
    paginate_by = 2

    def get_queryset(self):
        queryset = super().get_queryset()
        search = self.request.GET.get('search')
        if search:
            return Book.objects.filter(
                title__icontains=search
            )

book/templates/book.html:

<form class="form-inline my-2 my-lg-0" method="get" action="{% url 'book:search' %}">{% csrf_token %}
    <input style="font-size: 12px; width: 200px" class="form-control mr-sm-2" name="search" type="search" placeholder="Book Name" aria-label="Search">
    <button class="btn btn-outline-primary my-2 my-sm-0" type="submit">Search</button>
</form>

book/templates/search.html:

<div id="customContents">
    {% block customContents %}
    {% if book_list %}
    <ul>
        {% for book in book_list %}
        <li>{{ book.title }}</li>
        {% empty %}
        {% endfor %}
    </ul>

    {% if is_paginated %}

    <div class="pagination">
            <span class="page-links">
                {% if page_obj.has_previous %}
                    <a href="?page={{ page_obj.previous_page_number }}">previous</a>
                {% endif %}
                {% if page_obj.has_next %}
                    <a href="?page={{ page_obj.next_page_number }}">next</a>
                {% endif %}
            </span>
    </div>
    {% endif %}
    {% else %}
    <h3> No result found. </h3>
    {% endif %}
    {% endblock %}
</div>

book/urls:

app_name = 'book'
urlpatterns = [
    path('', views.HomePageView.as_view(), name='home'),
    path('search/', views.SearchResultView.as_view(), name='search'),
    path('<slug:slug>/', views.BookDetailView.as_view(), name='detail'),
]

只有这样才能正常工作:

class SearchResultView(generic.ListView):
    template_name = 'book/search.html'
    model = Book
    context_object_name = 'book_list'
    paginate_by = 2
    queryset = Book.objects.filter(
                title__icontains='Python'
            )

1
你能添加完整的回溯吗? - neverwalkaloner
1
你可以使用 Django 分页。而且,不需要使用 len() 进行测试,只需简单地执行 if books_with_title: 就可以了。 - MD. Khairul Basar
如果 search 是假的,那么你不返回任何东西。 - Willem Van Onsem
@WillemVanOnsem 我已经将其删除并更改了代码,但仍然面临相同的问题。 - SpellTheif
你误解了,应该在if search语句之外使用return queryset.none()。因为最初可能不存在search参数。 - Willem Van Onsem
显示剩余5条评论
2个回答

2

你的get_queryset()方法返回None。因为你在查询字符串中传递的不是search,而是page=2。所以,你的search变量是None。如果条件失败,get_queryset()将返回None

return queryset.filter(title='no result found')放在条件之外。

def get_queryset(self):
    queryset = super().get_queryset()
    search = self.request.GET.get('search')
    if search:
        books_with_title = queryset.filter(title__icontains=search)
        if len(books_with_title) > 0:
            return books_with_title

        books_with_author = queryset.filter(authors__name=search)
        if len(books_with_author) > 0:
            return books_with_author

        books_with_publisher = queryset.filter(publisher__name=search)
        if len(books_with_publisher) > 0:
            return books_with_publisher

    return queryset.filter(title='no result found')

@Jinx 尝试更改这个 - search = self.request.GET.get('page') - MD. Khairul Basar

2
您需要在查询字符串中覆盖 search 参数,因为您不需要重复它。有一堆关于如何处理这个问题的答案在时间累积过程中在这个问题中

这是您需要修复的错误:

<a href="?page={{ page_obj.previous_page_number }}">previous</a>

(并且对于“下一页”链接也是同样的操作。)
然后一切都应该像广告一样正常工作。
另外,您可以将搜索参数作为URL的一部分,但这会使搜索可缓存(取决于您的站点好坏),并需要JavaScript将输入移动到URL中。
要在Django中纯粹地执行此操作,您需要将搜索结果转移到仅验证搜索参数然后重定向到实际搜索列表的RedirectView
同样,这种方法有一些副作用,最明显的是对返回按钮的影响。
因此,我建议您查看链接答案中的查询字符串修改,如果您想采取不同的路线,请发布另一个问题以了解您的偏好。

其中一个解决方案对我有用。只是想知道如何通过某种方式覆盖“search”参数?我不认为自己手动更改过它。 - SpellTheif
当您创建以问号开头的链接时,您实际上会删除任何先前的查询字符串(也称为Django放置在QueryDict中的GET参数)。由于您的搜索表单使用GET方法,因此浏览器将表单元素转换为查询字符串,因此您的“search”参数位于查询字符串中。 - Melvyn Sopacua
让我看看您需要翻译的内容。 - SpellTheif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接