2014-04-02 21 views
17

Bardzo często widzę konstrukcje jakDjango ORM - objects.filter() vs. objects.all(). Filter() - który z nich jest preferowany?

MyModel.objects.all().filter(...) 

który zwróci QuerySet domyślnego Mananger. Początkowo all() wydaje się być zupełnie zbędne, ponieważ

MyMode.objects.filter(...) 

dostarcza ten sam rezultat.

to jednak wydaje się być wyjątkiem domyślnego tylko Managera, ponieważ z dwóch poniższych stwierdzeń zawartych w dokumentacji Django:

Fragment fromt rozdziale „Dodawanie dodatkowych metod Manager”

niestandardową Metoda menedżera może zwrócić wszystko, co chcesz. Nie ma ona , aby zwrócić zestaw kwerend.

Definicja metody all() Manager:

wszystko() Zwraca kopię bieżącego queryset (lub queryset podklasy). Może to być przydatne w sytuacjach, w których warto przekazać albo menedżera modelu lub QuerySet i wykonać dalsze filtrowanie wyniku . Po wywołaniu all() na dowolnym obiekcie, na pewno będziesz miał do pracy zestaw kwerend .

To wydaje się trochę sprzeczne ze mną. Z jednej strony Django daje swobodę, aby metoda menedżera mogła zwracać dowolne, a z drugiej strony wymaga zestawu QuerySet dla metody all(). Mam świadomość, że każdy menedżer ma metodę get_queryset, która jest wywoływana przez all(). Ale kto powstrzymuje mnie przed przesłonięciem all() w moim menedżerze niestandardowym? Chociaż zgadzam się, byłoby to złe.

  • Więc o ile widzę, metoda all() nie gwarantuje powrotu QuerySet. Co dokładnie zwraca MyModel.objects? Czy to stwierdzenie wywołuje all()? lub `get_queryset()?

  • Czy wolisz MyModel.objects.filter(...) lub MyModel.objects.all().filter(...). A jeśli tak, dlaczego?

  • Czy spotkałeś kiedyś nieudolnych menedżerów, którzy bałaganią tymi metodami w niepożądany sposób?

Odpowiedz

33

Sposób all() na stanowisku kierownika zaledwie delegatów get_queryset(), jak widać w Django source code:

def all(self): 
    return self.get_queryset() 

Więc to po prostu sposób, aby uzyskać QuerySet od Manager. Może to być przydatne, aby mieć pewność, że masz do czynienia z QuerySet, a nie z Menedżerem, ponieważ MyModel.objects zwraca menedżera.

Na przykład, jeśli chcesz iteracyjne nad wszystkimi rzeczami, ty nie to zrobić:

for item in MyModel.objects: 
    # do something with item 

Ponieważ nie można iteracyjne nad Manager. Jednak all() zwraca QuerySet, ty może iteracyjne nad queryset:

for item in MyModel.objects.all(): 
    # do something with item 

Generalnie, należy nigdy zastępować all(). Można nadpisać get_queryset(), ale ta metoda musi zwrócić się do zestawu kwerendy o .

Jeśli chcesz użyć metody filtrowania, takiej jak filter() lub exclude(), możesz już mieć zestaw QuerySet, because these methods are proxied to the QuerySet. Więc nie musisz robić czegoś takiego jak all().filter().

+0

Dziękuję za referencje źródłowe. To bardzo wyjaśniało. Pomogło mi to zrozumieć kwerendy django o wiele więcej! –

+0

Czy to była odpowiedź na twoje pytanie? Czy możesz rozważyć zaakceptowanie tej odpowiedzi? http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – rednaw

3
  1. MyModel.objects zwraca instancję menedżera. all() return get_query_set(). Myślę, że wszystko jest tam, kiedy potrzebujesz wszystkich obiektów.
  2. Wolę MyModel.objects.filter() ponieważ druga to tylko jedno wywołanie metody i nie potrzebuję wszystkich obiektów, jeśli filtruję :)
  3. To zależy od celu. Ale jeśli przesłonią podstawową metodę menedżera, zwracają ten sam format wyniku (np.QuerySet)
+1

Więc odpowiedź brzmi "' objects.filter() '' jest preferowany, ponieważ pisanie '' all() '', gdy w rzeczywistości robisz _nie_ chcesz, aby wszystkie obiekty nie były pythonic ". –