2011-03-01 20 views
9

Czy istnieje sposób na paginację rawqueryset przy użyciu wbudowanej paginacji Django? kiedy rzutuję go na listę, powoduje to błąd na mojej twarzy ... TypeError: oczekiwany ciąg znaków lub obiekt Unicode, znaleziono NoneType. Czy istnieje sposób obejścia tego?Paginacja django i RawQuerySet

Odpowiedz

14

udało mi się to osiągnąć stosując następujący:

paginator = Paginator(files, 12) 
paginator._count = len(list(files)) 

Kod w django.core.paginator.py:

  • sprawdza dostępność czy _count jest ustawiony
  • jeśli nie spróbuje uruchomić .count(), który nie istnieje
  • jeśli nie, to spróbuje zwykłego len

len na raw_queryset nie działa ale konwersja rzeczywisty obiekt paginator do listy prac znaleźć dla mnie w Django 1.3

+7

Oczywiście DŁ (lista (pliki)) jest bardzo nieefektywne pamięci dla dużych surowych zbiorów zapytań. Biorąc pod uwagę, że uruchomiłeś zapytanie, możesz zamiast tego uruchomić inne zapytanie z COUNT (*) i przypisać je do paginator._count, o ile liczba wyników nie zmieni się między poszczególnymi zapytaniami. Alternatywnie różne systemy DBMS mają sposoby na umieszczenie całkowitej liczby wierszy w każdym wierszu zapytania, jeśli wyniki zapytania ulegają ciągłym zmianom. – Chris

+0

Niestety, [RawQuerySet .__ getitem__()] (https://code.djangoproject.com/browser/django/trunk/django/db/models/query.py?rev=17381#L1517) lista wywołań (self) mimo to - więc zostanie całkowicie załadowany do pamięci, gdy tylko nazwiesz 'paginator.get_page()'. Aby tego uniknąć, myślę, że powinieneś podklasować RawQuerySet i upewnić się, że twój surowy SQL ma LIMIT/OFFSET - a nawet wtedy stracisz pamięć podręczną wyniku normalnego zestawu zapytań, więc dwukrotnie uzyskasz dostęp do qs [0] trafi dwukrotnie w DB. – AdamKG

+0

Tak, uderzy dwa razy. Właśnie to odkryłem dla siebie. Najlepiej napisać BARDZO wydajny sql dla tego surowego zapytania i zamiast przekazywać surowy zestaw zapytań do len (list()) i do paginatora najpierw oceniasz zestaw zapytań, wykonując pętlę nad nim. Podobnie jak l = [pozycja dla pozycji w zapytaniu], a następnie przekazać ją l zarówno do paginatora, jak i len (l). To daje tylko jedno połączenie z bazą danych. –

4

można ustawić ręcznie liczyć atrybut dla obiektu RawQuerySet:

items = Item.objects.raw("select * from appitem_item") 

def items_count(): 
    cursor = connection.cursor() 
    cursor.execute("select count(*) from appitem_item") 
    row = cursor.fetchone() 
    return row[0] 

items.count = items_count 

dla @Rockallite

>>> class A(): 
... def b(self): 
...  print 'from b' 
... 
>>> 
>>> (A()).b() 
from b 
>>> def c(): 
... print 'from c' 
... 
>>> a = A() 
>>> a.b = c 
>>> a.b() 
from c 
+0

django.core.paginator.Paginator szuka metody 'count()'. Zatem ustawienie właściwości 'count' nie działa. – Rockallite

+0

Dlaczego, testowałeś to? Oczywiście, to hack, ale użyłem go. Mam na myśli to, że w Pythonie można zastąpić jedną metodę drugą. –

+0

Rockallite, dodałem kod, aby zilustrować, jak działa ten hack –

-2
qs.filter(**pfilter).distinct().extra(select={'test': 'COALESCE(`psearch_program`.`eu_price`, 999999999)'}).extra(order_by=['test']) 
+0

-1: wyjaśnij, co się robi, z czym jest kompatybilność z itp. –