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()
できます。