2009-12-18 8 views
20

Sagen wir, ich habe eine Liste von Fotos nach Erstellungsdatum geordnet, wie folgt:Gibt es eine clevere Möglichkeit, das vorherige/nächste Element mit dem Django ORM zu erhalten?

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

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

Ich habe ein beliebiges Foto-Objekt photo_x. Gibt es eine einfache Möglichkeit, die vorherigen und nächsten Fotos nach Position im Queryset zu suchen? Außerdem würde ich gerne umrunden wenn ich am Anfang/Ende stehe und es nicht scheitern lassen wenn das nur 1 oder 2 Fotos sind.

Antwort

32

Sie haben Glück! Django erstellt get_next_by_foo und get_previous_by_foo Methoden standardmäßig für DateField & DateTimeField solange sie nicht null=True haben.

Zum Beispiel:

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

Und wenn Sie das Ende eines Satzes erreichen wird es eine DoesNotExist Ausnahme auslösen, die Sie einfach als Trigger verwenden könnten zu Beginn des Satzes zurück:

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

Weiterführende Literatur: Extra instance methods

+0

Danke, ich wusste, dass so etwas existiert. Ich konnte einfach nicht daran denken. –

+0

Ich bin froh, dass Sie das gesucht haben. Freut mich, helfen zu können. – jathanism

0

Um jathanism Antwort, seine sehr nützlich, ABER get_next_by_FOO und get_previous_by_FOO Millisekunden ignorieren ... zum Beispiel wird es nicht für Objekte arbeiten in Schleife erstellt:

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 und get_previous_by_foo sind praktisch, aber sehr begrenzt - sie helfen Ihnen nicht, wenn Sie bestellen auf mehr als einem Feld oder einem Nicht-Datum-Feld.

Ich schrieb django-next-prev als eine allgemeinere Implementierung der gleichen Idee. In Ihrem Fall könnten Sie einfach dies tun, da Sie die Bestellung in Ihrem Meta festgelegt haben:

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) 

Wenn Sie auf eine andere Kombination von Feldern, nur die queryset passieren bestellen wollte:

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

Paket funktioniert super, danke fürs Teilen. – DragonBobZ

Verwandte Themen