¿Hay alguna forma inteligente de obtener el elemento anterior / siguiente mediante el ORM de Django?

Digamos que tengo una lista de fotos ordenadas por fecha de creación, como sigue:

class Photo(models.Model): title = models.Char() image = models.Image() created = models.DateTimeField(auto_now_add=True) class Meta: ordering = ('-created',) 

Tengo un objeto foto arbitrario photo_x. ¿Hay una manera fácil de encontrar las fotos anteriores y siguientes por posición en el queryset? Además, me gustaría envolverme si estoy al principio / al final y que no falle si solo hay 1 o 2 fotos.

¡Estás de suerte! Django crea los métodos get_next_by_foo y get_previous_by_foo de forma predeterminada para DateField y DateTimeField siempre que no tengan null=True .

Por ejemplo:

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

Y si llega al final de un conjunto, generará una excepción DoesNotExist , que podría usar fácilmente como un activador para volver al principio del conjunto:

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

Lectura adicional : métodos de instancia adicionales

get_next_by_foo y get_previous_by_foo son útiles, pero muy limitados: no le ayudan si realiza un pedido en más de un campo o un campo sin fecha.

Escribí django-next-prev como una implementación más genérica de la misma idea. En su caso, simplemente puede hacer esto, ya que ha establecido el orden en su 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) 

Si desea ordenar en otra combinación de campos, simplemente pase el queryset:

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

Para responder jathanism, es útil, BUT get_next_by_FOO y get_previous_by_FOO ignoran milisegundos … por ejemplo, no funcionará para objetos creados en bucle:

 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.