在Django中获取下一个和上一个对象

x33g5p2x  于 2023-08-08  发布在  Go
关注(0)|答案(7)|浏览(121)

我在找一本漫画书的下一期和上一期。简单地更改id号或通过添加日期进行过滤是行不通的,因为我没有按顺序添加问题。
这就是我的视图是如何设置的,它适用于prev_issue,并返回前一个对象,但它返回next_issue的最后一个对象,我不知道为什么。

def issue(request, issue_id):
    issue = get_object_or_404(Issue, pk=issue_id)
    title = Title.objects.filter(issue=issue)
    prev_issue = Issue.objects.filter(title=title).filter(number__lt=issue.number)[0:1]
    next_issue = Issue.objects.filter(title=title).filter(number__gt=issue.number)[0:1]

字符串

mspsb9vt

mspsb9vt1#

添加order_by子句以确保它按number排序。

next_issue = Issue.objects.filter(title=title, number__gt=issue.number).order_by('number').first()

字符串

rbpvctlc

rbpvctlc2#

我知道这有点晚,但对于其他人来说,django确实有更好的方法来做到这一点,请参阅https://docs.djangoproject.com/en/1.7/ref/models/instances/#django.db.models.Model.get_previous_by_FOO
所以这里的答案应该是

next_issue = Issue.get_next_by_number(issue, title=title)

字符串
Django管理者通过一点Meta类的清晰度来做到这一点。

r8uurelv

r8uurelv3#

如果需要查找按字段值排序的nextprevious对象,并且这些字段不是Date*类型,则查询会稍微复杂一些,因为:

  • [:1]限制的具有相同值的对象上进行排序将总是对多个对象产生相同的结果;
  • 对象本身可以包含在结果集中。

以下是查询集,它也考虑了主键以产生正确的结果(假设OP中的number参数不是唯一的,并省略了title参数,因为它与示例无关):

上一页:

prev_issue = (Issue.objects
    .filter(number__lte=issue.number, id__lt=instance.id)
    .exclude(id=issue.id)
    .order_by('-number', '-id')
    .first())

字符串

下一页:

next_issue = (Issue.objects
    .filter(number__gte=issue.number, id__gt=instance.id)
    .exclude(id=issue.id)
    .order_by('number', 'id')
    .first())

velaa5lx

velaa5lx4#

from functools import partial, reduce
from django.db import models

def next_or_prev_instance(instance, qs=None, prev=False, loop=False):

    if not qs:
        qs = instance.__class__.objects.all()

    if prev:
        qs = qs.reverse()
        lookup = 'lt'
    else:
        lookup = 'gt'

    q_list = []
    prev_fields = []

    if qs.query.extra_order_by:
        ordering = qs.query.extra_order_by
    elif qs.query.order_by:
        ordering = qs.query.order_by
    elif qs.query.get_meta().ordering:
        ordering = qs.query.get_meta().ordering
    else:
        ordering = []

    ordering = list(ordering)

    if 'pk' not in ordering and '-pk' not in ordering:
        ordering.append('pk')
        qs = qs.order_by(*ordering)

    for field in ordering:
        if field[0] == '-':
            this_lookup = (lookup == 'gt' and 'lt' or 'gt')
            field = field[1:]
        else:
            this_lookup = lookup
        q_kwargs = dict([(f, get_model_attr(instance, f))
                         for f in prev_fields])
        key = "%s__%s" % (field, this_lookup)
        q_kwargs[key] = get_model_attr(instance, field)
        q_list.append(models.Q(**q_kwargs))
        prev_fields.append(field)
    try:
        return qs.filter(reduce(models.Q.__or__, q_list))[0]
    except IndexError:
        length = qs.count()
        if loop and length > 1:
            return qs[0]
    return None

next_instance = partial(next_or_prev_instance, prev=False)
prev_instance = partial(next_or_prev_instance, prev=True)

字符串

qyuhtwio

qyuhtwio5#

请注意,不要使用object.get(pk=object.pk + 1)这类东西,如果删除该pk处的对象,则会发生IntegrityError,因此始终使用查询集
参观者:

''' Useage '''
"""
    # Declare our item
    store = Store.objects.get(pk=pk)
    # Define our models
    stores = Store.objects.all()
    # Ask for the next item
    new_store = get_next_or_prev(stores, store, 'next')
    # If there is a next item
    if new_store:
        # Replace our item with the next one
        store = new_store
"""

''' Function '''
def get_next_or_prev(models, item, direction):
    '''
    Returns the next or previous item of
    a query-set for 'item'.

    'models' is a query-set containing all
    items of which 'item' is a part of.

    direction is 'next' or 'prev'
    
    '''

    getit = False
    if direction == 'prev':
        models = models.reverse()
    for m in models:
        if getit:
            return m
        if item == m:
            getit = True
    if getit:
        # This would happen when the last
        # item made getit True
        return models[0]
    return False

字符串
original author

用法

# you MUST call order by to pass in an order, otherwise QuerySet.reverse will not work
qs = Model.objects.all().order_by('pk')
q = qs[0]
prev = get_next_or_prev(qs, q, 'prev')
next = get_next_or_prev(qs, q, 'next')

7uhlpewt

7uhlpewt6#

对我很有效

next_post = Blog.objects.filter(date__lte=self.object.date, published=True).exclude(id=self.object.id).order_by('-date').first()
next_post = next_post if next_post else Blog.objects.filter(published=True).first()
previous_post = Blog.objects.filter(date__gte=self.object.date, published=True).exclude(id=self.object.id).order_by('date').first()
previous_post = previous_post if previous_post else Blog.objects.filter(published=True).last()

字符串

ss2ws0br

ss2ws0br7#

next_obj_id = int(current_obj_id)+ 1 next_obj = Model.objects.filter(id=next_obj_id).first()
prev_obj_id= int(current_obj_id)- 1 prev_obj = Model.objects.filter(id=prev_obj_id).first()
你在这里没有什么可失去的...这对我很管用

相关问题