Django分页开销与排序

时间:2011-07-11 16:53:59

标签: django sorting pagination

我尝试使用一些排序选项在Django中实现分页结构,但是我无法弄清楚如何正确地执行此操作。

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>

然而,正如您所看到的,我需要获取所有Employer个对象的每个导航,这个示例效果很好。之后Paginator根据页码处理查询中的对象。但是,我认为分页应该在查询期间完成,并且只根据页码获取我想要的X对象。当然,我可以用这种方式修改代码,但我无法弄清楚为什么人们会使用Paginator,尽管有这样的开销。我可能会忽略一个细节...

我的第二个问题是我如何应用排序列表?我应该修改我的url并传递排序方法和页码,并根据它们通过排序方法得到问题并将其提交给Paginator吗?

这对我来说似乎合情合理,但我只是想知道在django中有没有更好的办法。

由于

3 个答案:

答案 0 :(得分:6)

Django对于延迟加载数据非常聪明,这使得这些查询非常有效。让我们来看看您的请求会发生什么......

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

至于你的排序问题,我会说你只是修改你建议的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) # Replace pk with your default.
    sort = VALID_SORTS.get(sort_key, DEFAULT_SORT)

    eList = Employer.objects.filter(eminence__lt=4).order_by(sort)

答案 1 :(得分:0)

我强烈建议使用endless_pagination。这是一个awsum应用程序。 在这里查看示例项目:https://github.com/venkasub/endless_pagination_example

答案 2 :(得分:0)

实际上Paginator依赖于QuerySet的切片。切片依赖于特定的数据库 - 如果django db adapter支持它(例如将切片限制转移到SQL查询 - 对于像mysql这样的LIMIT x OFFSET y或其他db的其他东西)。如果支持,则查询仅提取给定页面的行 我相信对于MySQL来说这个功能现在被禁用了(我正在研究Django 1.3),因为OFFSET子句存在性能问题。