2011-07-26 10 views
5

Myślę, że najlepiej będzie to wyjaśnić na przykładzie.Czy mogę kontrolować GROUP BY w aplikacji django 1.3?

Oto jakie dane będzie wygląda następująco:

|project   | 
|id|name   | 
|1 |some project | 
|2 |my other project| 

|run         | 
|id|project_id|start_time |result | 
|1 |1   |1305732581845|something| 
|2 |1   |1305732593721|nothing | 
|3 |2   |1305732343721|nothing | 
|4 |2   |1305732556821|something| 

Chciałbym być w stanie uzyskać cały zestaw rekordów z każdego z najnowszymi biegnie przez projekt. Zapytania SQL będzie wyglądać mniej więcej tak:

SELECT *, MAX("run"."start_time") 
FROM "run"  
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id") 
GROUP BY "project"."id" 

ten powróci mi wszystkie kolumny w obu tabelach do najnowszej przebiegu projektu, co jest dobre, to jest dokładnie to, czego potrzebuję.

Tak więc, próbując znaleźć ekwiwalent django w django 1.3, po prostu nie mogę znaleźć odpowiedniego sposobu na zrobienie tego. Jeśli robię coś takiego:

Run.objects.annotate(Max('start_time')) 

Wygenerowany zapytań SQL będzie wyglądać mniej więcej tak:

SELECT 
"run"."id", "run"."result", "run"."project_id", "project"."id", "project"."name", 
MAX("run"."start_time") 
FROM "run" 
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id") 
GROUP BY "run"."id", "run"."result", "run"."project_id", "project"."id", "project"."name" 

To nie wróci mi odpowiednie wyniki grupy przez jest niepoprawna dla czego chcę. Wierzę w poprzednich wersjach Django przyszły poprawnie i wyraźnie określone grupy przez klauzuli w zapytaniu następujących ale wydaje się nie działać w 1.3:

q = Run.objects.annotate(Max('start_time')) 
q.query.group_by = [("project", "id")] 

w 1.3 to generuje dokładnie to samo zapytanie, jak nie ręcznie modyfikując group_by właściwość w zapytaniu.

Próbowałem również logicznie w oparciu o udokumentowane zachowanie .values ​​() przed i po wywołaniu adnotate(), ale nie działało ono zgodnie z oczekiwaniami. Kiedy próbowałem to:

q = Run.objects.values('project__id').annotate(Max('start_time')).values('id') 

skończyło się z zapytaniem jak to:

SELECT 
"run"."id", "run"."project_id" 
MAX("run"."start_time") 
FROM "run" 
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id") 
GROUP BY "run"."id", "run"."project_id" 

Czy ktoś może wskazać mi właściwy sposób, aby robić to, co robię, bez żadnej z następujących czynności:

  • Używanie surowego sql - jaki byłby sens używania orm, gdy ciągle muszę generować własne zapytania?
  • Korzystanie z .extra (select = {'latest': 'somequery'}) - dlaczego powinienem używać podkwerend, gdy idealnie poprawne zapytanie bez podzapytań może dać mi to, czego chcę.
  • Używanie wielu zapytań do przechwytywania tych samych danych - jeszcze raz, dlaczego powinienem wykonać wiele zapytań, aby uzyskać wyniki dostępne w 1?

Odpowiedz

1

tl; dr: Django nie pozwalają kontrolować klauzuli GROUP BY, ale ogranicza go do pracy we wszystkich smakach SQL więc nie mogę robić, co chcę.

Zostało mi wskazane, że oryginalne zapytanie, które próbuję wygenerować za pomocą ORM django, nie jest faktycznie poprawne dla wszystkich smaków SQL.Oto odświeżające zapytania szukałem:

SELECT *, MAX("run"."start_time") 
FROM "run"  
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id") 
GROUP BY "project"."id" 

Jeżeli dana osoba stara się wybrać coś, co nie jest w GROUP BY w MSSQL będą one rzeczywiście pojawia się błąd. Wydaje mi się więc, że django faktycznie nie powinno pozwolić mi wygenerować takiego zapytania i zasadniczo próbuję rozwiązać mój problem nieprawidłowo.

0

Jest to dość łatwe i szczegółowe w sekcji adnotacji dokumentów, a nie w żadnej poprzedniej wersji można ręcznie ustawić grupę przez.

YourModel.objects.values('this_is_your_group_by', 'even_a_second_field').annotate(sum=Sum('your_field')) 
+0

To nie zwróci całego zestawu rekordów dla każdego wiersza. Poda mi tylko wartości z kolumn na liście wartości. Oznacza to, że nie mogę uzyskać danych z kolumn bez grupowania według kolumn i niestety potrzebuję identyfikatorów przebiegu. – mockobject

+0

'wartości (" zgrupowania, ...). Adnotate(). Wartości ("more_fields_to_show_here") Upewnij się, że dodajesz nazwę pola dodanego przez adnotację do wartości term po adnotacji Naprawdę powinieneś przeczytać https://docs.djangoproject.com/en/1.3/topics/db/aggregation/#order-of-annotate-and-values-clauses – John

+1

Zapomniałem wspomnieć, że była to pierwsza metoda, którą wypróbowałem, ponieważ na podstawie dokumentacji wydawało się to logiczną drogą. Nie zadziałało jednak zgodnie z oczekiwaniami. Wszystkie wartości w tych ostatnich wartościach kończą się w klauzuli group_by. Czytałem dokumentację, która po prostu nie działa zgodnie z oczekiwaniami, chyba że robię z nią coś bardzo nie tak. Zaktualizuję oryginalne pytanie, aby zauważyć, że próbowałem tego i jakie były wyniki, było to tylko niedopatrzenie, gdy pisałem to pytanie. – mockobject