Есть ли умный способ получить предыдущий / следующий элемент, используя Django ORM? - PullRequest
20 голосов
/ 19 декабря 2009

Скажем, у меня есть список фотографий, упорядоченных по дате создания, следующим образом:

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

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

У меня есть произвольный объект Photo photo_x. Есть ли простой способ найти предыдущие и следующие фотографии по позиции в наборе запросов? Кроме того, я хотел бы обернуться, если я нахожусь в начале / конце, и у меня не будет ошибок, если только 1 или 2 фотографии.

Ответы [ 3 ]

32 голосов
/ 19 декабря 2009

Вам повезло! Django по умолчанию создает get_next_by_foo и get_previous_by_foo методы для DateField & 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.

Дополнительное чтение: Дополнительные методы экземпляра

2 голосов
/ 28 апреля 2017

get_next_by_foo и get_previous_by_foo удобны, но очень ограничены - они не помогут вам, если вы заказываете более одного поля или поле без даты.

Я написал django-next-prev как более общую реализацию той же идеи. В вашем случае вы можете просто сделать это, так как вы установили порядок в своей мета:

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)
0 голосов
/ 09 августа 2016

Для ответа на 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.
...