2011-03-01 4 views
9

Есть ли способ разбивать страницы на rawqueryset, используя встроенную разбивку на страницы django? , когда я бросаю его в список, он бросает мне ошибку ... TypeError: ожидаемая строка или объект Unicode, обнаружен NoneType. Есть ли способ обойти это?django pagination и RawQuerySet

ответ

14

мне удалось добиться этого с помощью следующего:

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

Код в django.core.paginator.py:

  • проверяет, является ли для _count установить
  • если нет, то пытается для запуска .count(), который не существует
  • если нет, то пытается использовать простой len

LEN на raw_queryset не работает, но преобразование фактического объекта Paginator к списку работ найти для меня в Django 1.3

+7

Очевидно LEN (список (файлов)) очень неэффективна памяти для больших наборов исходных запросов. Если вы знаете запрос, который был запущен, вы можете запустить другой запрос с помощью COUNT (*) и назначить его для paginator._count, если количество результатов не будет изменяться между каждым запросом. В качестве альтернативы, у разных СУБД есть способы вложить общее количество строк в каждую строку запроса, если результаты запроса постоянно меняются. – Chris

+0

К сожалению, [RawQuerySet .__ getitem__()] (https://code.djangoproject.com/browser/django/trunk/django/db/models/query.py?rev=17381#L1517) вызывает список (сам) в любом случае - поэтому он будет полностью загружен в память, как только вы назовете 'paginator.get_page()'. Чтобы этого избежать, я думаю, вам придется подклассировать RawQuerySet и убедиться, что ваш сырой SQL имеет LIMIT/OFFSET, и даже тогда вы потеряете кэш результатов обычного набора запросов, поэтому дважды обращайтесь к qs [0] дважды ударит БД. – AdamKG

+0

Да, он ударит дважды. Я просто открыл для себя это тоже. Поэтому лучше всего писать ОЧЕНЬ эффективный sql для этого необработанного набора запросов и вместо передачи необработанного запроса на len (list()), а для paginator вы сначала оцениваете набор запросов, перебирая его. Подобно l = [item для элемента в наборе запросов], а затем передайте это l как для paginator, так и для len (l). Это дает вам только один вызов базы данных. –

4

Вы можете установить кол атрибут вручную для объекта 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 

для @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 ищет метод 'count()'. Поэтому настройка свойства 'count' не работает. – Rockallite

+0

Почему, вы его протестировали? Конечно, это взломать, но я использовал его. Я имею в виду, что в python вы можете заменить один метод другим. –

+0

Rockallite, я добавил код, чтобы проиллюстрировать, как работает этот хак –

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

-1: объясните, что делается, с чем совместимость и т. Д. –