有没有一种聪明的方法来使用Django ORM获取上一个/下一个项目?

时间:2009-12-18 22:18:49

标签: python django django-models

说我有一个按创建日期排序的照片列表,如下所示:

class Photo(models.Model):
    title = models.Char()
    image = models.Image()
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ('-created',)

我有一个任意的Photo对象photo_x。有没有一种简单的方法可以在查询集中按位置查找上一张和下一张照片?另外,如果我只是一张或两张照片,我想在开始/结束时使用它并且不会失败。

3 个答案:

答案 0 :(得分:32)

你很幸运! Django默认为get_next_by_foo&创建get_previous_by_fooDateField方法。 DateTimeField,只要他们没有null=True

例如:

>>> from foo.models import Request
>>> r = Request.objects.get(id=1)
>>> r.get_next_by_created()
<Request: xyz246>

如果到达集合的末尾,它将引发DoesNotExist异常,您可以轻松地将其作为触发器返回到集合的开头:

>>> r2 = r.get_next_by_created()
>>> r2.get_next_by_created()
...
DoesNotExist: Request matching query does not exist.

进一步阅读:Extra instance methods

答案 1 :(得分:2)

get_next_by_foo和get_previous_by_foo非常方便,但非常有限 - 如果您在多个字段或非日期字段中进行订购,它们将无法帮助您。

我写了django-next-prev作为同一想法的更通用的实现。在您的情况下,您可以这样做,因为您已经在Meta中设置了排序:

from next_prev import next_in_order, prev_in_order
from .models import Photo

photo = Photo.objects.get(...)
next = next_in_order(photo)
prev = prev_in_order(photo)

如果您想在其他一些字段组合上订购,只需传递查询集:

photos = Photo.objects.order_by('title')
photo = photos.get(...)
next = next_in_order(photo, qs=photos)

答案 2 :(得分:0)

对于jathanism的答案,它有用,但 get_next_by_FOO get_previous_by_FOO 会忽略毫秒...例如,它不适用于在循环中创建的对象:

for i in range(100):
    Photo.objects.create(title='bla', ...)

obj = Photo.objects.first()
obj.get_previous_by_created()

DoesNotExist: Photo matching query does not exist.