2009-12-18 3 views
20

Dire que j'ai une liste de photos classées par date de création, comme suit:Existe-t-il une manière intelligente d'obtenir l'élément précédent/suivant en utilisant l'ORM de Django?

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

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

J'ai un photo_x arbitraire objet photo. Y at-il un moyen facile de trouver les photos précédentes et suivantes par position dans le jeu de requête? En outre, je voudrais emballer si je suis au début/fin et l'ai pas échouer si le sont seulement 1 ou 2 photos.

Répondre

32

Vous avez de la chance! Django crée les méthodes get_next_by_foo et get_previous_by_foo par défaut pour DateField & DateTimeField tant qu'elles n'ont pas null=True.

Par exemple:

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

Et si vous arrivez à la fin d'une série, il déclenche une exception DoesNotExist, que vous pouvez facilement utiliser comme un déclencheur pour revenir au début du jeu:

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

Pour en savoir plus: Extra instance methods

+0

Merci, je savais que quelque chose comme ça existait je ne pouvais tout simplement pas y penser. –

+0

Je suis heureux que ce soit ce que vous cherchiez. Heureux de pouvoir aider. – jathanism

0

Pour réponse jathanism, son uTILE, MAIS get_next_by_FOO et get_previous_by_FOO ignorer millisecondes ... par exemple, il ne fonctionnera pas pour les objets créés dans la boucle:

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 et get_previous_by_foo sont à portée de main, mais très limités - ils ne vous aident pas si vous commandez sur plus d'un champ, ou un champ non-date. J'ai écrit django-next-prev comme une implémentation plus générique de la même idée. Dans votre cas, vous pouvez tout cela, puisque vous avez défini l'ordre dans votre 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 vous vouliez commander sur une autre combinaison de champs, il suffit de passer la queryset:

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

Le forfait fonctionne très bien, merci pour le partage. – DragonBobZ

Questions connexes