Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 688
Jason Christa Avatar asked Dec 18 '09 22:12

Jason Christa


People also ask

How do I get the second last record in Django?

user "q = Salaries. objects. all(). order_by('-salary)[1]" .. it will give you second highest salary record..

Which operators can be used to access the fields in the object by Django ORM?

You use a period (.) to access the fields in the Django ORM object.

Is Django ORM good?

The Django ORM is a very powerful tool, and one of the great attractions of Django. It makes writing simple queries trivial, and does a great job of abstracting away the database layer in your application. And sometimes, you shouldn't use it.


2 Answers

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

like image 189
jathanism Avatar answered Sep 21 '22 20:09

jathanism


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) 
like image 34
Greg Avatar answered Sep 21 '22 20:09

Greg