2013-04-23 10 views
10

私はしばらく前に使ったdjangoページネーションのコード例がいくつかありました。私は間違っているかもしれませんが、コードを見てみると、それは膨大なメモリを浪費するようです。私はよりよい解決策を探していた、ここではコードです:私はこのコードのsubtltiesのかわからないけど効率的なページ番号付けとdjangoでのデータベースクエリ

# in views.py 
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 

... 
...  

def someView(): 
    models = Model.objects.order_by('-timestamp') 
    paginator = Paginator(models, 7) 
    pageNumber = request.GET.get('page') 

    try: 
     paginatedPage = paginator.page(pageNumber) 
    except PageNotAnInteger: 
     pageNumber = 1 
    except EmptyPage: 
     pageNumber = paginator.num_pages 
    models = paginator.page(pageNumber) 

    return render_to_resp (..... models ....) 

それがどのように見えるか、コードの最初の行は、データベースからすべての単一のモデルを取得しますからそれを押し込む。それから、それは、ユーザがHTML GETからどのページにいるかに基づいてそれをチャンクアップするPaginatorに渡されます。 paginatorはこれを何らかの形で受け入れ可能にしていますか?これは完全にメモリが非効率的ですか?それが非効率な場合、どのように改善できますか?

また、関連するトピックです。誰かがない場合:

Model.objects.all()[:40] 

このコードは、すべてのモデルがメモリ内に押し込まれ、我々は彼らの40をスプライスしていることを意味するのでしょうか?どちらが悪いですか。それとも、40個のオブジェクトだけを照会してメモリ期間に押し込むということですか?

ありがとうございました!

答えて

16

mymodel.objects.all()はリストではなくクエリーセットを生成します。クエリーセットは怠惰です。要求は発行されず、実際に使用するまで何も行われません。また、クエリセットをスライスしても、データベース全体に負荷がかからず、データベースにアクセスする前にSQLクエリに制限とオフセットが追加されます。

-1

paginatorを使用するとメモリが不十分ではありません。クエリーセットは遅れて評価されます。電話Paginator(models, 7)では、modelsはこの時点まで評価されていないクエリセットです。だから今までデータベースがヒットしていません。また、モデルのすべてのインスタンスを含むリストは、この時点ではメモリ内にありません。

paginatedPage = paginator.page(pageNumber)というページを取得する場合は、このクエリセットでスライスが行われます。この時点でデータベースがヒットし、モデルのインスタンスを含むクエリーセットが返されます。スライスすると、ページにあるオブジェクトが返されます。したがって、スライスされたオブジェクトだけがメモリ内にあるリストに入れられます。 1つのページに10個のオブジェクトを表示したい場合、これらの10個のオブジェクトだけがメモリに残ります。

誰かがそうしたとき。

Model.objects.all()[:40] 

リストをスライスすると、新しいリストが作成されます。あなたの場合、リストは40要素だけで作成され、メモリのどこかに格納されます。それ以外のリストは存在しないので、Modelのすべてのインスタンスがメモリー内に含まれるリストはありません。

+0

Yeah but .. modelsは、データベース全体のモデルオブジェクトのすべてで、最初の行にそのオブジェクトが正しくロードされています。あなたはかわい子のようなものを殺していると言っていますか? URの2番目の答えは、はい新しいリストが作成されますが、古いものはまだちょうどそこに右ですか?それともそれはただの黙示録が消えるのだろうか? –

+0

2番目の答えは、古いリストの参照カウントが0になるため、ガベージコレクションが発生したときに古いリストに到達する手段がないため、ガベージコレクションされます。 –

+0

最初の答えでは、modelsはデータベース内のすべてのモデルオブジェクトであり、ビューの全期間にわたってメモリに格納されます。そして、それ以外の場合は、djangoは特定のページにどのようなオブジェクトを表示するのかを知っていなければなりません。 Djangoはすべてのオブジェクトを提供し、それからあなたが望むページを伝えたら、djangoがスライスして新しいリストを返します。 –

0

上記の情報を使用して、私はビュー関数デコレータを思いついた。 json_list_objectsはdjanogオブジェクトをdjangoオブジェクトの既知の関係フィールドのjson-ready python dictsに取り込み、jsonifiedリストを{count:results:}として返します。

他にも役立つことがあります。

def with_paging(fn): 
    """ 
    Decorator providing paging behavior. It is for decorating a function that 
    takes a request and other arguments and returns the appropriate query 
    doing select and filter operations. The decorator adds paging by examining 
    the QueryParams of the request for page_size (default 2000) and 
    page_num (default 0). The query supplied is used to return the appropriate 
    slice. 
    """ 
    @wraps(fn) 
    def inner(request, *args, **kwargs): 
    page_size = int(request.GET.get('page_size', 2000)) 
    page_num = int(request.GET.get('page_num', 0)) 
    query = fn(request, *args, **kwargs) 
    start = page_num * page_size 
    end = start + page_size 
    data = query[start:end] 
    total_size = query.count() 
    return json_list_objects(data, overall_count=total_size) 
    return inner 
関連する問題