2009-12-18 1 views
20

Скажем, у меня есть список фотографий, заказанных по дате создания, а именно:Есть ли умный способ получить предыдущий/следующий элемент с помощью 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 фотографии.

ответ

32

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

Дальнейшее чтение: Extra instance methods

+0

Спасибо, я знал, что что-то подобное существовало, я просто не мог думать об этом. –

+0

Я рад, что это то, что вы искали. Рад быть в состоянии помочь. – jathanism

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. 
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) 

Если вы хотите сделать заказ на какой-либо другой комбинации полей, просто передать QuerySet:

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

Пакет отлично работает, спасибо за обмен. – DragonBobZ

Смежные вопросы