Django dispose de l'excellente nouvelle fonction annotate() pour les querysets. Cependant, je n'arrive pas à la faire fonctionner correctement pour plusieurs annotations dans un seul queryset.
Par exemple,
tour_list = Tour.objects.all().annotate( Count('tourcomment') ).annotate( Count('history') )
Une visite peut contenir plusieurs entrées de commentaires et d'historique. J'essaie de savoir combien de commentaires et d'entrées d'historique existent pour cette visite. Le résultat
history__count and tourcomment__count
seront incorrectes. S'il n'y a qu'un seul appel à annotate(), la valeur sera correcte.
Il semble qu'il y ait une sorte d'effet multiplicatif provenant des deux LEFT OUTER JOIN
s. Par exemple, si une visite a 3 historiques et 3 commentaires, 9 sera la valeur de comptage pour les deux. 12 historiques + 1 commentaire = 12 pour les deux valeurs. 1 historique + 0 commentaire = 1 historique, 0 commentaire (celui-ci renvoie les valeurs correctes).
L'appel SQL résultant est :
SELECT `testapp_tour`.`id`, `testapp_tour`.`operator_id`, `testapp_tour`.`name`, `testapp_tour`.`region_id`, `testapp_tour`.`description`, `testapp_tour`.`net_price`, `testapp_tour`.`sales_price`, `testapp_tour`.`enabled`, `testapp_tour`.`num_views`, `testapp_tour`.`create_date`, `testapp_tour`.`modify_date`, `testapp_tour`.`image1`, `testapp_tour`.`image2`, `testapp_tour`.`image3`, `testapp_tour`.`image4`, `testapp_tour`.`notes`, `testapp_tour`.`pickup_time`, `testapp_tour`.`dropoff_time`, COUNT(`testapp_tourcomment`.`id`) AS `tourcomment__count`, COUNT(`testapp_history`.`id`) AS `history__count`
FROM `testapp_tour` LEFT OUTER JOIN `testapp_tourcomment` ON (`testapp_tour`.`id` = `testapp_tourcomment`.`tour_id`) LEFT OUTER JOIN `testapp_history` ON (`testapp_tour`.`id` = `testapp_history`.`tour_id`)
GROUP BY `testapp_tour`.`id`
ORDER BY `testapp_tour`.`name` ASC
J'ai essayé de combiner les résultats de deux querysets qui contiennent un seul appel à annotate (), mais cela ne fonctionne pas correctement... Vous ne pouvez pas vraiment garantir que l'ordre sera le même. et cela semble trop compliqué et désordonné donc j'ai cherché quelque chose de mieux...
tour_list = Tour.objects.all().filter(operator__user__exact = request.user ).filter(enabled__exact = True).annotate( Count('tourcomment') )
tour_list_historycount = Tour.objects.all().filter( enabled__exact = True ).annotate( Count('history') )
for i,o in enumerate(tour_list):
o.history__count = tour_list_historycount[i].history__count
Merci pour toute aide. Stackoverflow m'a sauvé la mise par le passé avec de nombreuses questions déjà résolues, mais je n'ai pas encore trouvé de réponse à celle-ci.