Подтвердить что ты не робот

Есть ли умный способ получить предыдущий/следующий элемент с помощью Django ORM?

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

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

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

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

4b9b3361

Ответ 1

Вам повезло! 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

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)

Ответ 3

Чтобы ответить 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.