如何用其他获取变量对Django进行分页?

vag*_*ond 65 django pagination

我在Django中使用分页时遇到问题.以下面的URL为例:

http://127.0.0.1:8000/users/?sort=first_name
Run Code Online (Sandbox Code Playgroud)

在此页面上,我按其first_name对用户列表进行排序.没有排序GET变量,它默认按id排序.

现在,如果我点击下一个链接,我希望以下网址:

http://127.0.0.1:8000/users/?sort=first_name&page=2
Run Code Online (Sandbox Code Playgroud)

相反,我失去了所有得到的变量,最终得到了

http://127.0.0.1:8000/users/?page=2
Run Code Online (Sandbox Code Playgroud)

这是一个问题,因为第二页按id而不是first_name排序.

如果我使用request.get_full_path,我最终会得到一个丑陋的URL:

http://127.0.0.1:8000/users/?sort=first_name&page=2&page=3&page=4
Run Code Online (Sandbox Code Playgroud)

解决办法是什么?有没有办法访问模板上的GET变量并替换页面的值?

我正在使用Django文档中描述的分页,我的偏好是继续使用它.我使用的模板代码与此类似:

{% if contacts.has_next %}
    <a href="?page={{ contacts.next_page_number }}">next</a>
{% endif %}
Run Code Online (Sandbox Code Playgroud)

mpa*_*paf 55

我认为提出的自定义标签过于复杂,这就是我在模板中所做的:

<a href="?{% url_replace request 'page' paginator.next_page_number %}">
Run Code Online (Sandbox Code Playgroud)

标签功能:

@register.simple_tag
def url_replace(request, field, value):

    dict_ = request.GET.copy()

    dict_[field] = value

    return dict_.urlencode()
Run Code Online (Sandbox Code Playgroud)

如果url_param尚未包含在url中,则会添加值.如果它已经存在,它将被新值替换.这是一个适合我的简单解决方案,但是当url具有多个具有相同名称的参数时不起作用.

您还需要从视图中将RequestContext请求实例提供给模板.更多信息:

http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/

  • 您甚至可以重构,不需要将`request`作为参数传递.请参阅此答案http://stackoverflow.com/a/2160298/1272513 (4认同)

sko*_*l00 36

我认为url_replace解决方案可以更优雅地重写

from urllib.parse import urlencode
from django import template

register = template.Library()

@register.simple_tag(takes_context=True)
def url_replace(context, **kwargs):
    query = context['request'].GET.copy()
    query.update(kwargs)
    return query.urlencode()
Run Code Online (Sandbox Code Playgroud)

模板字符串简化为

<a href="?{% url_replace page=paginator.next_page_number %}">
Run Code Online (Sandbox Code Playgroud)

这允许替换多个键但不允许使用重复键进行查询.

  • 谢谢,这个有效!对于Python 3,请使用`urllib.parse.urlencode()`.请参阅[此问题](http://stackoverflow.com/a/28906913/4323648). (4认同)
  • 缺点-它将在网址中创建重复的参数,例如:&p = 2&p = 3&p = 4` (4认同)
  • 删除多个 page=&amp;page 值。只需添加: if query.get('page'): query.pop('page') (3认同)

vag*_*ond 12

经过一番游戏,我找到了一个解决方案......虽然我不知道它是不是真的很好.我更喜欢更优雅的解决方案.

无论如何,我将请求传递给模板,并能够通过request.GET访问所有GET变量.然后我遍历GET字典,只要变量不是页面我就打印它.

{% if contacts.has_previous %}
    <a href="?page={{ contacts.previous_page_number }}{% for key,value in request.GET.items %}{% ifnotequal key 'page' %}&{{ key }}={{ value }}{% endifnotequal %}{% endfor %}">previous</a>
{% endif %}

<span class="current">
    Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
</span>

{# I have all of this in one line in my code (like in the previous section), but I'm putting spaces here for readability.  #}
{% if contacts.has_next %}
    <a href="?page={{ contacts.next_page_number }}
        {% for key,value in request.GET.items %}
            {% ifnotequal key 'page' %}
                &{{ key }}={{ value }}
            {% endifnotequal %}
        {% endfor %}
    ">next</a>
{% endif %}
Run Code Online (Sandbox Code Playgroud)

  • 这种方法有效,但有一些缺陷:1.它违反了DRY原则 - 你重复你的代码,这意味着如果你想要改变它的内容,你必须在你复制它的所有地方改变它.2.它严重违反模型 - 视图 - 控制器(或模型 - 模板 - 视图,如Django创建者所称)设计模式 - 模板应该用于仅渲染数据.3.它会导致冗余/无意义的GET参数一直传递 - 这可能不是一个大问题,但在我看来,过滤掉这些参数会更优雅. (2认同)
  • 对之前评论的补充:如果您坚持在模板中处理此问题,那么我认为您应该编写自定义模板标签,将`request` 作为参数,然后将您的参数字符串打印回模板。 (2认同)

mik*_*iku 7

在你的views.py身上,你会以某种方式访问​​你排序的标准,例如first_name.您需要将该值传递给模板并将其插入其中以记住它.

例:

{% if contacts.has_next %}
    <a href="?sort={{ criteria }}&page={{ contacts.next_page_number }}">next</a>
{% endif %}
Run Code Online (Sandbox Code Playgroud)


Jos*_*iño 5

可以创建一个上下文处理器以在任何应用分页的地方使用它。

例如,在my_project/my_app/context_processors.py

def getvars(request):
    """
    Builds a GET variables string to be uses in template links like pagination
    when persistence of the GET vars is needed.
    """
    variables = request.GET.copy()

    if 'page' in variables:
        del variables['page']

    return {'getvars': '&{0}'.format(variables.urlencode())}
Run Code Online (Sandbox Code Playgroud)

将上下文处理器添加到 Django 项目设置中:

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
    'django.core.context_processors.i18n',
    'django.core.context_processors.request',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
     ...
    'my_project.my_app.context_processors.getvars',
)
Run Code Online (Sandbox Code Playgroud)

然后,在您的模板中,您可以在分页时使用它:

<div class="row">
    {# Initial/backward buttons #}
    <div class="col-xs-4 col-md-4 text-left">
        <a href="?page=1{{ getvars }}" class="btn btn-rounded">{% trans 'first' %}</a>
        {% if page_obj.has_previous %}
            <a href="?page={{ page_obj.previous_page_number }}{{ getvars }}" class="btn btn-rounded">{% trans 'previous' %}</a>
        {% endif %}
    </div>

    {# Page selection by number #}
    <div class="col-xs-4 col-md-4 text-center content-pagination">
        {% for page in page_obj.paginator.page_range %}
            {% ifequal page page_obj.number %}
                <a class="active">{{ page }}</a>
            {% else %}
                <a href="?page={{ page }}{{ getvars }}">{{ page }}</a>
            {% endifequal %}
        {% endfor %}
    </div>

    {# Final/forward buttons #}
    <div class="col-xs-4 col-md-4 text-right">
        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}{{ getvars }}" class="btn btn-rounded">{% trans 'next' %}</a>
        {% endif %}
        <a href="?page={{ paginator.num_pages }}{{ getvars }}" class="btn btn-rounded">{% trans 'last' %}</a>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

无论您在请求中使用什么 GET 变量,它们都将附加在?page=GET 参数之后。


Omi*_*aha 5

改善这种方式:

使用urlencodefromdjango而不是urllib, 以防止参数UnicodeEncodeError错误unicode

模板标签:

from django.utils.http import urlencode

@register.simple_tag(takes_context=True)
def url_replace(context, **kwargs):
    query = context['request'].GET.dict()
    query.update(kwargs)
    return urlencode(query)
Run Code Online (Sandbox Code Playgroud)

模板:

<!-- Pagination -->
<div class="pagination">
 <span class="step-links">
   {% if coupons.has_previous %}
    <a href="?{% url_replace page=objects.previous_page_number %}">Prev</a>
   {% endif %}
   <span class="current">
    Page {{ objects.number }} of {{ objects.paginator.num_pages }}
   </span>
   {% if objects.has_next %}
    <a href="?{% url_replace page=objects.next_page_number %}">Next</a>
   {% endif %}
  </span>
</div>
Run Code Online (Sandbox Code Playgroud)