django 分页和获取参数

c0vxltue  于 2023-02-14  发布在  Go
关注(0)|答案(4)|浏览(130)

** Django 1.11.4**

我已经建立了一个搜索表单的方法=“获取”。搜索表单有很多的形式。然后这个输入值作为获取参数在网址传输。
问题是如何获得分页。数据库包含成千上万的对象。分页是必要的。
这是文档告诉我们的:
https://docs.djangoproject.com/en/1.11/topics/pagination/#using-paginator-in-a-view
它是这样暗示的:

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

但这会破坏所有的get参数。
我发明的是:

<a href="{{ request.get_full_path }}&page={{ object_list.previous_page_number }}">previous</a>

这是可行的,但这是愚蠢的,如果一个人向前和向后切换页面,它会产生这样的网址结尾:

page=2&page=3&page=2

我已经看过Google是如何处理这个问题的。在url的中间他们有start=30。并且改变这个参数:开始=20,开始=40。所以,它们交换了。
你能帮助我理解如何在Django中保留获取参数和切换页面吗?当然是用一种优雅的方式。

zu0ti5jz

zu0ti5jz1#

一般的解决方案是定义一个“自定义模板标记”(一个函数),它保留完整的URL,但更新传递给它的GET参数。
注册后,您可以在模板中使用此功能:

<a href="?{% query_transform page=contacts.previous_page_number %}">previous</a>

要定义和注册自定义模板标记,请在Python文件中包含以下代码:

from django import template

register = template.Library()

@register.simple_tag(takes_context=True)
def query_transform(context, **kwargs):
    query = context['request'].GET.copy()
    for k, v in kwargs.items():
        query[k] = v
    return query.urlencode()
  • 感谢Ben提供的query_transform代码,这是his code对python 3的一个改编。
    为什么此方法优于手动重建URL:

如果您以后决定在URL中需要其他参数:1.你不需要更新模板中的所有链接。2.你不需要传递所有重新构造URL到模板所需的参数。

vhmi4jdf

vhmi4jdf2#

通常,为了保留GET参数,你只需手工重写它们,应该不会有太多的情况需要这样做。

&page={{page}}&total={{total}}

您可以将其抽象为模板include或自定义模板标记。
https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/
此外,您还可以创建一个字符串过滤器,它将URL参数作为字符串以及您要更改的值的dict。然后,过滤器可以解析参数字符串,更新值,然后将字符串重新组合为URL参数。

{{ request.get_full_path | update_param:'page=8' }}
jhiyze9q

jhiyze9q3#

这就是我所做的,发现更容易。虽然很多不是更好的方法!

param = ""
        if search_programs:
            qs = qs.filter(title__icontains=search_programs)
            param = param + f"&search_programs={search_programs}"
        if level:
            qs = qs.filter(level__icontains=level)
            param = param + f"&level={level}"
        if category:
            qs = qs.filter(sector__icontains=category)
            param = param + f"&category={category}"
        paginator = Paginator(qs, 16)
        page_number = self.request.GET.get('page')
        page_obj = paginator.get_page(page_number)
        context = {
            'page_obj': page_obj,
            "param": param
        }
        return render(self.request, self.template_name, context)
# in html
 <a href="?page={{ page_obj.next_page_number }}{{param}}" class="page-link">next</a>
vlju58qv

vlju58qv4#

细分

我解决这个问题的方法是将Django的Paginator类子类化并添加我需要的东西。
您需要覆盖init方法,以允许自己从视图传递request和form对象,这样您就可以检索request.GET参数并将它们与form.fields进行比较。您希望只允许在表单中预定义的GET参数名称。否则,您将删除它们。
一旦你子类化了Pagination类,你就可以在www.example.com文件中使用它views.py,向它传递额外的请求和表单参数,然后你就可以按照Django文档中的建议渲染你的模板,但是现在你可以访问你可以使用的paginator.first_params,paginator.last_params,page.previous_params和page.next_params变量。
pagination.py

import urllib

from django.core.paginator import Paginator as DjangoPaginator, EmptyPage

class Paginator(DjangoPaginator):

    def __init__(self, *args, **kwargs):
        request = kwargs.pop('request', None)
        form = kwargs.pop('form', None)
        super().__init__(*args, **kwargs)
        
        self.params = {key: value for key, value in request.GET.items() if key in form.fields.keys()}

        self.first_params = urllib.parse.urlencode({**self.params, 'page': 1})
        self.last_params = urllib.parse.urlencode({**self.params, 'page': self.num_pages})

    def get_page(self, *args, **kwargs):
        page = super().get_page(*args, **kwargs)
    
        try:
            page.previous_page_number = page.previous_page_number()
        except EmptyPage:
            page.previous_page_number = None
        
        try:
            page.next_page_number = page.next_page_number()
        except EmptyPage:
            page.next_page_number = None
        
        page.previous_params = urllib.parse.urlencode({**self.params, 'page': page.previous_page_number})
        page.next_params = urllib.parse.urlencode({**self.params, 'page': page.next_page_number})
    
        return page

views.py

from .pagination import Paginator

paginator = Paginator(queryset, per_page, request=request, form=form)
page = paginator.get_page(page_number)

分页. html

{% if page %}
    <nav id="pagination">
        {% if page.has_previous %}
            <a href="?{{ paginator.first_params }}">&laquo; First</a>
            <a href="?{{ page.previous_params }}" rel="prev">Previous</a>
        {% endif %}
        <span class="current">
            Page {{ page.number }} of {{ page.paginator.num_pages }}.
        </span>
        {% if page.has_next %}
            <a href="?{{ page.next_params }}" rel="next">Next</a>
            <a href="?{{ paginator.last_params }}">Last &raquo;</a>
        {% endif %}
    </nav>
{% endif %}

相关问题