如何使用其他get变量对Django进行分页?
我在中使用分页时遇到问题。以下面的URL为例:如何使用其他get变量对Django进行分页?,django,pagination,Django,Pagination,我在中使用分页时遇到问题。以下面的URL为例: http://127.0.0.1:8000/users/?sort=first_name 在这个页面上,我按照用户的名字对用户列表进行排序。如果没有sort GET变量,它默认为按id排序 现在,如果单击下一个链接,我希望看到以下URL: http://127.0.0.1:8000/users/?sort=first_name&page=2 相反,我丢失了所有get变量,并以 http://127.0.0.1:8000/users/?p
http://127.0.0.1:8000/users/?sort=first_name
在这个页面上,我按照用户的名字对用户列表进行排序。如果没有sort GET变量,它默认为按id排序
现在,如果单击下一个链接,我希望看到以下URL:
http://127.0.0.1:8000/users/?sort=first_name&page=2
相反,我丢失了所有get变量,并以
http://127.0.0.1:8000/users/?page=2
这是一个问题,因为第二页是按id排序的,而不是按名字排序的
如果我使用request.get_full_路径,我最终会得到一个丑陋的URL:
http://127.0.0.1:8000/users/?sort=first_name&page=2&page=3&page=4
解决办法是什么?是否有方法访问模板上的GET变量并替换页面的值
我正在使用中描述的分页,我的首选是继续使用它。我使用的模板代码与此类似:
{% if contacts.has_next %}
<a href="?page={{ contacts.next_page_number }}">next</a>
{% endif %}
{%if contacts.has_next%}
{%endif%}
在您的视图.py
中,您将以某种方式访问排序所依据的标准,例如名字
。您需要将该值传递给模板并将其插入其中以记住它
例如:
{% if contacts.has_next %}
<a href="?sort={{ criteria }}&page={{ contacts.next_page_number }}">next</a>
{% endif %}
{%if contacts.has_next%}
{%endif%}
玩了一会儿之后,我找到了一个解决方案。。。虽然我不知道它是否真的好。我想要一个更优雅的解决方案
无论如何,我将请求传递给模板,并且能够通过request.GET访问所有GET变量。然后我循环使用GET字典,只要变量不是page,我就打印它
{% 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 %}
{%if contacts.has_previous%}
{%endif%}
第{{contacts.paginator.num_pages}页中的第{{contacts.number}页。
{#我在代码中把所有这些都放在一行中(就像上一节一样),但是为了可读性,我在这里放了空格
{%if contacts.has_next%}
{%endif%}
您在视图中放置的每个此类链接都必须配备相关参数。没有可以转换的隐含魔法:
进入:
因此,您需要的是一些Sorter
object/class/function/snippet(任何适合这里的东西都不会过度),它的作用类似于django.core.paginator.paginator,但会处理sort
GET参数
可以这么简单:
sort_order = request.GET.get('sort', 'default-criteria')
<paginate, sort>
return render_to_response('view.html', {
'paginated_contacts': paginated_contacts, # Paginator stuff
'sort_order': sort_order if sort_oder != 'default-criteria' else ''
})
sort\u order=request.GET.GET('sort','default criteria')
返回render\u to\u响应('view.html'{
“分页的_联系人”:分页的_联系人,#分页器内容
“排序顺序”:如果排序顺序!=“默认条件”否则“排序顺序”
})
那么,在你看来:
{% if contacts.has_next %}
<a href="?page={{ contacts.next_page_number }}{%if sort_order%}&sort={{sort_oder}}{%endif%}">next</a>
{% endif %}
{%if contacts.has_next%}
{%endif%}
我可以变得更通用,但我希望您能理解这个概念。'path':request.get_full_path().rsplit('&page')[0],这里有一个用于构造查询字符串的有用的自定义模板标记
<a href="?{% make_query_string page=obj_list.next_page_number %}">Next page</a>
我认为建议的自定义标记太复杂,这是我在模板中所做的:
<a href="?{% url_replace request 'page' paginator.next_page_number %}">
href="?page={{ objects.next_page_number }}&{{path}}"
如果url_参数尚不在url中,则会添加值。如果它已经存在,则将被新值替换。这是一个适合我的简单解决方案,但当url有多个同名参数时,它就不起作用了
您还需要从视图向模板提供RequestContext请求实例。更多信息请点击此处:
我想说的是,从控制器生成下一个和上一个链接,然后将其传递到视图并从那里使用它。我将给你一个例子(更像一个伪代码): 然后在您看来,像这样使用它:
{% if contacts.has_next %}
<a href="?page={{ contacts.next_link }}">next</a>
{% endif %}
{%if contacts.has_next%}
{%endif%}
您需要返回上述GET。您可以通过调用
render_dict['GET'] = request.GET.urlencode(True)
return render_to_response('search/search.html',
render_dict,
context_instance=RequestContext(request))
然后你可以在模板中使用它来构建你的URL,例如
href="/search/client/{{ page.no }}/10/?{{ GET }}
可以创建上下文处理器,以便在应用分页的任何位置使用它 例如,在
my\u project/my\u app/context\u 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())}
将上下文处理器添加到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',
)
然后,在模板中,可以在分页时使用此选项:
<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>
{#初始/后退按钮}
{%如果页面_obj.has_previous%}
{%endif%}
{#按数字选择页面#}
{page_obj.paginator.page_range%}
{%ifequal page_obj.number%}
{%endifequal%}
{%endfor%}
{#最终/前进按钮}
{%如果页面_obj.has_next%}
{%endif%}
无论请求中有什么GET变量,它们都将附加在
?page=
GET参数之后。这是一种简单的方法
鉴于:
path = ''
path += "%s" % "&".join(["%s=%s" % (key, value) for (key, value) in request.GET.items() if not key=='page' ])
然后在模板中:
<a href="?{% url_replace request 'page' paginator.next_page_number %}">
href="?page={{ objects.next_page_number }}&{{path}}"
使用Django的分页,保存GET参数很简单 首先将GET参数复制到变量(在视图中): 并通过上下文字典将其发送到模板:
return render_to_response(template,
{'request': request, 'contact': contact, 'GET_params':GET_params}, context_instance=RequestContext(request))
您需要做的第二件事是使用它,在模板中的url调用(href)中指定它-例如(扩展基本分页html以处理额外的参数条件):
{%if contacts.has_next%}
{%if GET_params%}
{%else%}
{%endif%}
{%endif%}
我认为url\u替换解决方案可以更优雅地重写为
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()
将模板字符串简化为
<a href="?{% url_replace page=paginator.next_page_number %}">
通过以下方式改进:
使用django
中的urlencode
而不是urllib
,以防止unicode
参数出现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)
模板:
<!-- 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>
{%如果优惠券.has_previous%}
{%endif%}
第{{objects.paginator.num_pages}页中的第{{objects.number}页
{%if objects.has_next%}
{%endif%}
另一种url_编码解决方案,在本例中通过skoval00简化
我对那个版本有一些问题。第一,它不支持Unicode编码;第二,它对具有多个相同密钥的筛选器(如MultipleSelect wid)中断
{% if contacts.has_next %}
{% if GET_params %}
<a href="?{{GET_params.urlencode}}&page={{ contacts.next_page_number }}">next</a>
{% else %}
<a href="?page={{ contacts.next_page_number }}">next</a>
{% endif %}
{% endif %}
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()
<a href="?{% url_replace page=paginator.next_page_number %}">
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)
<!-- 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>
from django import template
from django.utils.html import mark_safe
register = template.Library()
@register.simple_tag(takes_context=True)
def url_replace(context, **kwargs):
query = context['request'].GET.copy()
for kwarg in kwargs:
try:
query.pop(kwarg)
except KeyError:
pass
query.update(kwargs)
return mark_safe(query.urlencode())
<a class="next" href="?{% url_replace p=objects.next_page_number%}">Next</a>
{% bootstrap_pagination page_obj extra=request.GET.urlencode %}
from urllib.parse import urlencode
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def url_replace(context, next_page):
query = context['request'].GET.copy().urlencode()
if '&page=' in query:
url = query.rpartition('&page=')[0] # equivalent to .split('page='), except more efficient
else:
url = query
return f'{url}&page={next_page}'
from urllib.parse import urlencode
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def url_replace(context, next_page):
if query.startswith('page') or not len(query):
new_url = f'page={next_page}'
elif '&page=' in query:
get_params = query.rpartition('&page=')[0] # equivalent to .split('page='), except more efficient
new_url = f'{get_params}&page={next_page}'
else:
new_url = f'{query}&page={next_page}'
return new_url
@register.simple_tag(takes_context=True)
def url_replace(context, **kwargs):
query = context['request'].GET.copy()
query.pop('page', None)
query.update(kwargs)
return query.urlencode()
@register.simple_tag(takes_context=True)
def url_replace(context, **kwargs):
query = context['request'].GET.copy()
for key in kwargs:
query[key] = kwargs[key]
return query.urlencode()
<a class="page-link" href="?{% url_replace p=1 q='bar'%}">
{% 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 %}