Django分页开销与排序 [英] Django pagination overhead with sorting
问题描述
我尝试使用某些排序方式在Django中实现分页结构,但我无法确定如何正确执行。
视图。 py
def search(request):
/ pre>
eList = Employer.objects.filter(eminence__lt = 4 ).order_by(' - eminence')
paginator = Paginator(eList,3)#显示每页3个联系人
page = request.GET.get('page' )
try:
employerList = paginator.page(page)
除了PageNotAnInteger:
employerList = paginator.page(1)
除了EmptyPage:
employerList = paginator.page(paginator.num_pages)
返回render_response(请求,雇主/ search.html,{'雇主列表':雇主列表})
search.html
< div class =pagination>
< span class =step-links>
{%如果employerList.has_previous%}
< a href =?page = {{employerList.previous_page_number}}> previous< / a>
{%endif%}
< span class =current> {{employerList.paginator.num_pages}}的页面{{employerList.number}}。< / span>
{%如果employerList.has_next%}
< a href =?page = {{employerList.next_page_number}}> next< / a>
{%endif%}
< / span>
< / div>
这个例子很好,但是你可以看到,对于每个导航,我需要得到所有的
雇主
对象。之后,Paginator
根据页码处理查询中的对象。但是,我认为分页应该在查询期间完成,只有根据页码才能得到我想要的X对象。当然,我可以修改代码,但是我不明白为什么人们使用Paginator
虽然有这样的开销。我可能会忽略一个细节...
我的第二个问题是如何应用排序我的列表?我应该修改我的
url
并传递排序方法和页码,并根据他们通过sort方法得到quesy,并将其赋予Paginator
?
这似乎是合理和罚款,但我只是想知道有没有更好的做法在django。
谢谢
解决方案Django对于延迟加载数据非常聪明,这使得这些查询非常有效。我们来看看你的请求会发生什么...
eList = Employer.objects.filter(eminence__lt = 4).order_by '-eminence')
##没有数据库查询。
paginator = Paginator(eList,3)
##没有数据库查询。
employerList = paginator.page(2)
## SELECT COUNT(*)FROM`yourproject_employer`
## WHERE`yourproject_employer`.`eminence`< 4
#强制迭代。与循环结果相同:
foo = list(employerList.object_list)
## SELECT * FROM`yourproject_employer`
## WHERE`yourproject_employer`.`eminence`< 4
## ORDER BY`yourproject_employer`.`eminence` DESC
## LIMIT 3 OFFSET 3
至于你的排序问题,我会说你只是按照你的建议修改
GET
参数。只要将非常小心地传递给数据库。例如,我会列出可能的排序并对此进行验证。这也意味着您不必公开数据库的内部工作。VALID_SORTS = {
pk:pk,
pkd:-pk,
em:eminence,
emd:-eminence,
}
DEFAULT_SORT ='pk'
def search(request):
sort_key = request.GET.get('sort',DEFAULT_SORT)#将pk替换为默认值。
sort = VALID_SORTS.get(sort_key,DEFAULT_SORT)
eList = Employer.objects.filter(eminence__lt = 4).order_by(sort)
I try to implement pagination structure in Django with some sort options however, I can't figure out how can I do that properly.
views.py
def search(request): eList = Employer.objects.filter(eminence__lt=4).order_by('-eminence') paginator = Paginator(eList, 3) # Show 3 contacts per page page = request.GET.get('page') try: employerList = paginator.page(page) except PageNotAnInteger: employerList = paginator.page(1) except EmptyPage: employerList = paginator.page(paginator.num_pages) return render_response(request, 'employer/search.html', {'employerList':employerList})
search.html
<div class="pagination"> <span class="step-links"> {% if employerList.has_previous %} <a href="?page={{ employerList.previous_page_number }}">previous</a> {% endif %} <span class="current"> Page {{ employerList.number }} of {{ employerList.paginator.num_pages }}.</span> {% if employerList.has_next %} <a href="?page={{ employerList.next_page_number }}">next</a> {% endif %} </span> </div>
This example works great however as you can see, for every navigation I need to get all
Employer
objects. After thatPaginator
handles the objects in query depending on page number. However, I think the pagination should be done during query and only get X objects that I want depending on page number. I can modify, of course, the code in that manner but I can't figure out why people usePaginator
although there is such overhead. I may overlook a detail...My second question is how can I apply sort my list ? Should I modify my
url
and passing a sort method and page number, and depending on them get the quesy by sort method and give it toPaginator
?This seems reasonable and fine by me but I just wonder is there any better approach to do in django.
Thanks
解决方案Django is very smart about lazy-loading the data, which makes these queries very efficient. Let's walk through what happens with your requests...
eList = Employer.objects.filter(eminence__lt=4).order_by('-eminence') ## No database query. paginator = Paginator(eList, 3) ## No database query. employerList = paginator.page(2) ## SELECT COUNT(*) FROM `yourproject_employer` ## WHERE `yourproject_employer`.`eminence` < 4 # Force iteration. Same as looping over results: foo = list(employerList.object_list) ## SELECT * FROM `yourproject_employer` ## WHERE `yourproject_employer`.`eminence` < 4 ## ORDER BY `yourproject_employer`.`eminence` DESC ## LIMIT 3 OFFSET 3
As for your sorting question, I would say to simply modify the
GET
arguments as you suggested. Just be very careful passing this to the database. I would, for example, make a list of possible sorts and verify against that. This also means you don't have to expose the inner-workings of your database.VALID_SORTS = { "pk": "pk", "pkd": "-pk", "em": "eminence", "emd": "-eminence", } DEFAULT_SORT = 'pk' def search(request): sort_key = request.GET.get('sort', DEFAULT_SORT) # Replace pk with your default. sort = VALID_SORTS.get(sort_key, DEFAULT_SORT) eList = Employer.objects.filter(eminence__lt=4).order_by(sort)
这篇关于Django分页开销与排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!