python - related - queryset object django




Requête Django qui obtient les objets les plus récents de différentes catégories (4)

À partir de Django 1.11 et grâce à Subquery et OuterRef et nous pouvons enfin construire une requête latest-per-group utilisant l' ORM .

hottest_cakes = Cake.objects.filter(
    baked_at=Subquery(
        (Cake.objects
            .filter(bakery=OuterRef('bakery'))
            .values('bakery')
            .annotate(last_bake=Max('baked_at'))
            .values('last_bake')[:1]
        )
    )
)

#BONUS, we can now use this for prefetch_related()
bakeries = Bakery.objects.all().prefetch_related(
    Prefetch('cake_set',
        queryset=hottest_cakes,
        to_attr='hottest_cakes'
    )
)

#usage
for bakery in bakeries:
    print 'Bakery %s has %s hottest_cakes' % (bakery, len(bakery.hottest_cakes))

J'ai deux modèles A et B Tous B objets B ont une clé étrangère à un objet A Étant donné un ensemble d'objets A , est-il possible d'utiliser l'ORM pour obtenir un ensemble d'objets B contenant l'objet le plus récent créé pour chaque objet A

Voici un exemple simplifié:

Class Bakery(models.Model):
    town = models.CharField()

Class Cake(models.Model):
    bakery = models.ForeignKey(Bakery)
    baked_at = models.DateTimeField()

Donc, je cherche une requête qui renvoie le gâteau le plus récent cuit dans chaque boulangerie à Anytown, États-Unis.


Cela devrait faire le travail:

from django.db.models import Max
Bakery.objects.annotate(Max('cake__baked_at'))

Pour autant que je sache, il n'y a pas de moyen unique de faire cela dans Django ORM.

Mais vous pouvez le diviser en deux requêtes:

bakeries = Bakery.objects.annotate(hottest_cake_baked_at=Max('cake__baked_at')) 
hottest_cakes = Cake.objects.filter(baked_at__in=[b.hottest_cake_baked_at for b in bakeries])

Si les ID des gâteaux progressent avec les horodatages bake_at, vous pouvez simplifier et désambiguïser le code ci-dessus (dans le cas où deux gâteaux arrivent en même temps, vous pouvez les obtenir tous les deux):

hottest_cake_ids = Bakery.objects.annotate(hottest_cake_id=Max('cake__id')).values_list('hottest_cak‌​e_id', flat=True)
hottest_cakes = Cake.objects.filter(id__in=hottest_cake_ids)

BTW crédits pour cela va à Daniel Roseman, qui a déjà répondu à une question similaire à moi:

http://groups.google.pl/group/django-users/browse_thread/thread/3b3cd4cbad478d34/3e4c87f336696054?hl=pl&q=

Si la méthode ci-dessus est trop lente, je connais également la seconde méthode - vous pouvez écrire du SQL personnalisé produisant uniquement les gâteaux les plus chauds dans les boulangeries pertinentes, le définir comme vue de la base de données, puis écrire le modèle Django non managé. Il est également mentionné dans le thread django-users ci-dessus. Lien direct vers le concept original est ici:

http://web.archive.org/web/20130203180037/http://wolfram.kriesing.de/blog/index.php/2007/django-nice-and-critical-article#comment-48425

J'espère que cela t'aides.


Si vous utilisez PostGreSQL, vous pouvez utiliser l'interface de Django pour DISTINCT ON :

recent_cakes = Cake.objects.order_by('bakery__id', '-baked_at').distinct('bakery__id')

Comme le disent les docs , vous devez order by les mêmes champs que vous distinct on . Comme Simon l'a souligné ci-dessous, si vous voulez faire un tri supplémentaire, vous devrez le faire dans Python-space.





greatest-n-per-group