2009-08-12 12 views
21

Django ma świetną nową funkcję adnotate() dla zapytań. Nie mogę jednak zmusić go do poprawnego działania wielu adnotacji w jednym zapytaniu.Django adnotate() wiele razy powoduje błędne odpowiedzi

Na przykład

tour_list = Tour.objects.all().annotate(Count('tourcomment')).annotate(Count('history')) 

Trasa może zawierać wiele tourcomment i historia wpisy. Próbuję uzyskać liczbę komentarzy i wpisów historii dla tej trasy. Uzyskane wartości będą niepoprawne. Wartości te będą niepoprawne. Jeśli istnieje tylko jedno wywołanie adnotacji(), wartość będzie poprawna.

Wydaje się, że istnieje pewien efekt multiplikatywny pochodzący z dwóch s. LEFT OUTER JOIN. Na przykład, jeśli trasa ma 3 historie i 3 komentarze, 9 będzie wartością dla obu. 12 historii + 1 komentarz = 12 dla obu wartości. 1 historia + 0 komentarzy = 1 historia, 0 komentarzy (to się dzieje, aby zwrócić prawidłowe wartości).

Powstały połączenia SQL jest:

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 

Próbowałem połączenie wyników z dwóch querysets które zawierają jeden wezwanie do opisywania(), ale to nie działa dobrze ... Nie można naprawdę gwarantuję, że zamówienie będzie takie samo. i wydaje się zbyt skomplikowany i niechlujny, więc szukałem czegoś lepszego ...

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 

Dzięki za pomoc. Stackoverflow uratował mój tyłek w przeszłości z wieloma już odpowiedział na pytania, ale nie byłem w stanie znaleźć odpowiedzi na to jeszcze.

Odpowiedz

0

Nie mogę zagwarantować, że rozwiąże to Twój problem, ale spróbuj dołączyć .order_by() do swojego połączenia. Czyli:

tour_list = Tour.objects.all().annotate(Count('tourcomment')).annotate(Count('history')).order_by() 

Powodem tego jest fakt, że Django musi wybrać wszystkie pola w klauzuli ORDER BY, która powoduje poza tym identyczny wyniki mają zostać wybrane. Dołączając .order_by(), całkowicie usuwasz klauzulę ORDER BY, co zapobiega temu. Aby uzyskać więcej informacji na ten temat, zobacz temat the aggregation documentation.

40

Dzięki za komentarz. To nie działało, ale skierowało mnie we właściwym kierunku. I w końcu udało się rozwiązać ten problem poprzez dodanie odrębny zarówno count() zwraca:

Count('tourcomment', distinct=True) 
+1

... który wciąż jest straszne rozwiązanie, jak to tylko odfiltrowuje wszystkie duplikaty z ogromnej wyniku – dragonroot

+1

To również działa tylko z Liczyć. Mam podobny problem z liczbą i sumą, a podczas gdy ustawienie różni się od prawdziwej, powoduje, że liczba jest dokładna, suma jest wciąż mnożona. – StephenTG

+0

Ponadto, dla opisu błędu "Sum" patrz: https: //code.djangoproject .com/ticket/10060 – sobolevn

Powiązane problemy