2009-06-25 17 views
27

私はQuerySetを持っていますが、qsと呼びましょう。これはこの問題とは関係のないいくつかの属性によって順序付けられています。オブジェクトがある場合は、objとしましょう。今度はobjのインデックスがqsのインデックスに、を効率的にとしています。私は.index()をPythonから、あるいはqsからそれぞれのオブジェクトをobjと比較してループすることができることを知っていますが、これを行う最善の方法は何ですか?私は高性能を求めており、それが私の唯一の基準です。クエリーセット内の要素のインデックスを取得

WindowsでDjango 1.0.2とともにPython 2.6.2を使用する。

+0

まず、更新のために、まずクエリセットが順序付けられていません。したがって、索引は反復ごとに異なる場合があります。任意のフィールド上で 'order_by'を実行する必要があり、次にVinayの答えをフォローすると、インデックスが必要な場合に役立ちます。 – Babu

+0

もし私たちが1000万のレコードを持っていれば、データベースの操作は難しいです。 – alexche8

答えて

13

実際にはDjangoのQuerySetはリストではなく、リストではありません(詳細はDjango documentation on QuerySetsを参照)。
このように、要素のインデックスを取得するためのショートカットはありません。私は平易な反復処理を行うのが最善の方法だと思います。

初心者の方では、できるだけ簡単な方法で要件を実装します(反復処理のように)。パフォーマンスの問題が本当にある場合は、フィールドの量が少ないクエリセットを作成するなど、いくつかの異なるアプローチを使用します。
いずれにしても、必要なことを確実に知っているときは、可能な限り遅くすることをお勧めします。
更新: DjangoのORMはこれをネイティブにサポートしておらず、生のSQLクエリ(documentation参照)を使用する必要があります。再び最良の選択肢であってもよいが、 - あなたは本当に本当のパフォーマンスの問題を参照する場合にのみ

+0

私は参照してください。私はSQLに最後に触れてからしばらくしていましたが、普通のSQLで可能で、DjangoのQuerySet APIを使用することが可能かもしれないと思いました。 –

+0

はい、これはオプションになる可能性があります。私は可能な解決策にそれを加えました。 –

50

コンパクトで、おそらく最も効率的な:。

for index, item in enumerate(your_queryset): 
    ... 
11

は、あなたのモデルは、主に標準装備され、例示の目的のためにと仮定すると、キーidを入力し、

list(qs.values_list('id', flat=True)).index(obj.id) 

objのインデックスは、qsにあります。 listを使用するとクエリーセットが評価されますが、元のクエリーセットではなく派生クエリーセットが評価されます。この評価では、SQLクエリを実行してIDフィールドのみを取得し、他のフィールドを取得する時間を浪費することはありません。

+1

これは、クエリーセットが結果をキャッシュしているので、後で実行するかどうかによって、より効率的であるか、元のクエリーセットを評価するだけでなく効率が低下する可能性があります。 –

+1

この方法に問題があります。 qs.values_list( 'id'、flat = True)は、各ステップで異なる値を返します。同じクエリで異なるインデックスを取得します。 – Virako

26

あなたはちょうどあなたが他のすべて(例えば、ランクを決定する場合)の中で座って、あなたがあなたの前にオブジェクトをカウントすることにより、すぐにそれを行うことができますオブジェクトの場所を知りたい場合は、次の

index = MyModel.objects.filter(sortField__lt = myObject.sortField).count() 
+4

この場合、 'sortField'を一意にすることも必要です。そうしないと、' myObject.sortField'に等しい 'sortField'を持つ最初の要素の位置が得られるからです。 – naktinis

+0

'.count() - 1'ではないでしょうか?たとえば、クエリーセットに1つのオブジェクトがある場合、インデックスは0です。 –

1

あなたはqueryset.extra(…)を使ってこれを行うことができますし、いくつかの生のSQLはそうです:

queryset = queryset.order_by("id") 
record500 = queryset[500] 

numbered_qs = queryset.extra(select={ 
    'queryset_row_number': 'ROW_NUMBER() OVER (ORDER BY "id")' 
}) 

from django.db import connection 
cursor = connection.cursor() 
cursor.execute(
    "WITH OrderedQueryset AS (" + str(numbered_qs.query) + ") " 
    "SELECT queryset_row_number FROM OrderedQueryset WHERE id = %s", 
    [record500.id] 
    ) 
index = cursor.fetchall()[0][0] 

index == 501 # because row_number() is 1 indexed not 0 indexed 
+0

はい、1,4,5,6 ....... 500のようなIDを持っていればいいですか? – alexche8

+0

@ alexche8それは私のために十数十の結果セットでうまくいく(後でページ付けする) – Jiaaro

関連する問題