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

前端 未结 3 792
谎友^
谎友^ 2020-12-29 05:50

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

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


        
相关标签:
3条回答
  • 2020-12-29 06:34

    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

    0 讨论(0)
  • 2020-12-29 06:36

    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.
    
    0 讨论(0)
  • 2020-12-29 06:44

    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)
    
    0 讨论(0)
提交回复
热议问题