2011-03-01 34 views
9

có cách nào để phân trang một rawqueryset bằng cách sử dụng phân vùng inbuilt của django không? khi tôi truyền nó vào một danh sách, nó ném một lỗi trong khuôn mặt của tôi ... TypeError: chuỗi dự kiến ​​hoặc đối tượng Unicode, NoneType tìm thấy. Có cách nào để giái quyết vấn đề này không?django pagination và RawQuerySet

Trả lời

14

tôi quản lý để đạt được điều đó bằng cách sử dụng sau đây:

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

Mã trong django.core.paginator.py:

  • kiểm tra cho dù _count được thiết lập
  • nếu không thì cố gắng để chạy .count() không tồn tại
  • nếu không thì hãy thử plain len

len trên raw_queryset không hoạt động nhưng chuyển đổi các đối tượng paginator thực tế vào một danh sách các công trình tìm cho tôi trong Django 1,3

+7

Rõ ràng len (danh sách (file)) là rất nhớ không hiệu quả cho các bộ truy vấn liệu lớn. Cho bạn biết truy vấn đã chạy, bạn có thể chạy truy vấn khác bằng COUNT (*) thay thế và gán truy vấn đó cho paginator._count miễn là số lượng kết quả sẽ không thay đổi giữa mỗi truy vấn. Cách khác DBMS có cách bạn có thể nhúng tổng số hàng trong mỗi hàng truy vấn nếu kết quả truy vấn liên tục thay đổi. – Chris

+0

Thật không may, [RawQuerySet .__ getitem__()] (https://code.djangoproject.com/browser/django/trunk/django/db/models/query.py?rev=17381#L1517) danh sách cuộc gọi (tự) anyway - vì vậy nó sẽ được nạp hoàn toàn vào bộ nhớ ngay khi bạn gọi 'paginator.get_page()'. Để tránh điều đó, tôi nghĩ bạn phải phân lớp RawQuerySet và đảm bảo rằng SQL thô của bạn có LIMIT/OFFSET - và thậm chí sau đó, bạn sẽ mất bộ đệm kết quả của một queryset bình thường, vì vậy truy cập qs [0] hai lần sẽ nhấn DB hai lần. – AdamKG

+0

Có nó sẽ nhấn hai lần. Tôi cũng mới khám phá ra nó. Vì vậy, tốt nhất bạn viết sql RẤT hiệu quả cho queryset thô đó và thay vì chuyển queryset thô sang len (list()) và để paginator bạn đầu tiên đánh giá queryset bằng cách lặp lại nó. Giống như l = [item cho item trong queryset] và sau đó truyền l cho cả paginator và len (l). Điều này cho phép bạn chỉ có một cuộc gọi cơ sở dữ liệu. –

4

Bạn có thể thiết lập các thuộc tính đếm bằng tay cho đối tượng RawQuerySet của bạn:

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 

cho @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 tìm phương thức 'count()'. Vì vậy, thiết lập thuộc tính 'count' không hoạt động. – Rockallite

+0

Tại sao bạn thử nghiệm nó? Tất nhiên, đó là một hack nhưng tôi đã sử dụng nó. Tôi có nghĩa là trong python bạn có thể thay thế một phương pháp khác. –

+0

Rockallite, tôi đã thêm mã để minh họa cách thức hoạt động của hack này –

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

-1: giải thích những gì đang được thực hiện, với khả năng tương thích với, v.v. –