如何从过滤的有序查询集中获取上一个和下一个对象?

时间:2009-11-07 08:11:23

标签: django django-models django-queryset

我有一个基于模型对象的页面,我希望有前一页和下一页的链接。我不喜欢我当前的解决方案,因为它需要评估整个查询集(获取ids列表),然后再评估两个get查询。当然有一些方法可以一次完成这个过程吗?

def get_prev_and_next_page(current_page):
    ids = list(Page.objects.values_list("id", flat=True))
    current_idx = ids.index(current_page.id)
    prev_page = Page.objects.get(id=ids[current_idx-1])
    try:
        next_page = Page.objects.get(id=ids[current_idx+1])
    except IndexError:
        next_page = Page.objects.get(id=ids[0])
    return (prev_page, next_page)

排序顺序在模型中定义,因此不必在此处理,但请注意,您不能假设ID是顺序的。

3 个答案:

答案 0 :(得分:8)

听起来Paginator设置为1的阈值会很好。

# Full query set...
pages = Page.objects.filter(column=somevalue)
p = Paginator(pages, 1)

# Where next page would be something like...
if p.has_next():
     p.page(p.number+1)

Documentation herehere

答案 1 :(得分:2)

我是Python和Django的新手,所以也许我的代码不是最优的,但请查看:

def get_prev_and_next_items(target, items):
    ''' To get previous and next objects from QuerySet '''
    found = False
    prev = None
    next = None
    for item in items:
        if found:
            next = item
            break
        if item.id == target.id:
            found = True
            continue
        prev = item
    return (prev, next)

并且考虑到这样的事情:

def organisation(request, organisation_id):
    organisation = Organisation.objects.get(id=organisation_id)
    ...
    prev, next = get_prev_and_next_items(organisation, Organisation.objects.all().order_by('type'))
    ...
    return render_to_response('reference/organisation/organisation.html', {
        'organisation': organisation,
        'prev': prev,
        'next': next,
    })

绝对不是“重”查询集的最佳选择,但在大多数情况下,它就像魅力一样。 :)

答案 2 :(得分:1)

查看django-next-prev,我写了它来解决这个问题。在这种情况下:

from next_prev import next_in_order, prev_in_order

def get_prev_and_next_page(current_page):
    page_qs = Page.objects.all()  # this could be filtered, or ordered
    prev_page = prev_in_order(current_page, page_qs)
    next_page = next_in_order(current_page, page_qs)
    return (prev_page, next_page)