サンプルからの名前付きタプル

Djangoでは、大量のデータを返すクエリを高速化するために、 values_list()



メソッドのvalues()



およびvalues_list()



ます。 最初のモデルではなく辞書、2番目のタプルを返します。 モデルインスタンスのように両方で作業することは便利ではありません。 しかし、私はそうしたくありません。標準collections



モジュールの名前付きタプルのおかげで、私はそうしません。



出会っていない人やまだ納得していない人のために、私は物事の現在の状態を示すコードを提供します:

qs = Item . objects . filter( ... )

for item in qs:

print item . title, item . amount

total += item . amount * item . price



#

qs = Item . objects . filter( ... ) . values( 'title' , 'amount' , 'price' )

for item in qs:

print item[ 'title' ], item[ 'amount' ]

total += item[ 'amount' ] * item[ 'price' ]



#

qs = Item . objects . filter( ... ) . values_list( 'title' , 'amount' , 'price' )

for item in qs:

print item[ 0 ], item[ 1 ]

total += item[ 1 ] * item[ 2 ]







辞書とタプルを使用したバリアントは、モデルほどきれいではありませんが、より速く動作し、必要なメモリが少なくなります。 名前付きタプルを使用すると、属性でフィールドにアクセスできます。 それらによって、私たちのコードはモデルのコードとほとんど変わりません。 したがって、付随するボーナス-多くの場合、コードを変更せずにモデルからタプルへ、またはその逆に切り替えることができ、コードを変更する必要がある場合、変更は最小限になります。 さらに、タプルはすべてのオブジェクトではなくクラスにフィールド名をディクショナリとして保存するため、メモリの使用量が少なくなります。これはそれ自体が素晴らしく、クエリ結果をキャッシュに入れることが重要になります。



名前付きタプルとは何ですか?



名前付きタプルはPython 2.6で登場し、指定された属性に従って要素へのアクセスが可能なタプルです。 デモ用の小さなコード:

>>> from collections import namedtuple

>>> Point = namedtuple( 'Point' , 'x y' . split())

>>> p = Point(x =11 , y =22 ) #

>>> p2 = Point( 11 , 22 ) # ...

>>> p1 == p2

True

>>> p[ 0 ] + p[ 1 ] #

33

>>> x, y = p # ...

>>> x, y

(11, 22)

>>> p . x + p . y #

33

>>> Point . _make([ 11 , 22 ]) #

Point(x=11, y=22)







NamedTuplesQuerySet



名前付きタプルを生成するQuerySet



子孫を作成します。 指定されたフィールドを持つすべてのクエリロジックがValuesQuerySet



ValuesQuerySet



QuerySet.values()



から返されるQuerySet.values()



実装されているという事実により、以下を発行する前に結果のみを処理できます。

from itertools import imap

from collections import namedtuple



from django.db.models.query import ValuesQuerySet



class NamedTuplesQuerySet (ValuesQuerySet):

def iterator ( self ):

#

extra_names = self . query . extra_select . keys()

field_names = self . field_names

aggregate_names = self . query . aggregate_select . keys()

names = extra_names + field_names + aggregate_names



#

tuple_cls = namedtuple( ' %s Tuple' % self . model . __name__, names)



results_iter = self . query . get_compiler( self . db) . results_iter()

#

return imap(tuple_cls . _make, results_iter)







そして、使いやすくするために、メソッドをQuerySet



割り当てます。

from django.db.models.query import QuerySet



def namedtuples ( self , * fields):

return self . _clone(klass = NamedTuplesQuerySet, setup = True , _fields = fields)

QuerySet . namedtuples = namedtuples







その後、モデル、辞書、タプルに関する記事の冒頭のコードは次のように書くことができます。

qs = Item . objects . filter( ... ) . namedtuples( 'title' , 'amount' , 'price' )

for item in qs:

print item . title, item . amount

total += item . amount * item . price







結果のクラスが利用可能なアクセラレータのvalues()



values_list()



の両方の機能を実行するのは面白いです。 そして、それはより良くまたはほぼ同様にそれを行い、同時により美しいコードを生成します。 多分いつかこれは彼らの交換につながるでしょう。



PSパッチと一緒にクラスコードをここから取り出すことができますgist.github.com/876324

PPSタプル内のフィールドの順序は、引数nametuples()



順序と一致しない場合があります。これは、高速化のためにスコア付けされます。 フィールドの並べ替えの実装は、必要に応じてValuesListQuerySet.iterator()



からValuesListQuerySet.iterator()



できます。



All Articles