Is there a clever way to get the previous/next item using the Django ORM?

无人久伴 提交于 2019-12-30 00:55:11

问题


Say I have a list of photos ordered by creation date, as follows:

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

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

I have an arbitrary Photo object photo_x. Is there an easy way to find the previous and next photos by position in the queryset? Also, I would like to wrap around if I am at the beginning/end and have it not fail if the are only 1 or 2 photos.


回答1:


You're in luck! Django creates get_next_by_foo and get_previous_by_foo methods by default for DateField & DateTimeField as long as they do not have null=True.

For example:

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

And if you reach the end of a set it will raise a DoesNotExist exception, which you could easily use as a trigger to return to the beginning of the set:

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

Further reading: Extra instance methods




回答2:


get_next_by_foo and get_previous_by_foo are handy, but very limited - they don't help you if you're ordering on more than one field, or a non-date field.

I wrote django-next-prev as a more generic implementation of the same idea. In your case you could just do this, since you've set the ordering in your 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)

If you wanted to order on some other combination of fields, just pass the queryset:

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



回答3:


To jathanism answer, its usefull, BUT get_next_by_FOO and get_previous_by_FOO ignore milliseconds... for example it will not work for objects created in loop:

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.


来源:https://stackoverflow.com/questions/1931008/is-there-a-clever-way-to-get-the-previous-next-item-using-the-django-orm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!