Есть ли умный способ получить предыдущий/следующий элемент с помощью 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 фотографии.
Ответы
Ответ 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.