QuerySet
values()
and values_list()
. The first instead of models returns dictionaries, the second tuples. Working with those and with others is not as convenient as with instances of models, they say, pay the guys for speed convenience. But I don’t want to, and thanks to the nominal tuples from the standard collections
module, I won’t.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 ]
>>> 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)
QuerySet
, which will produce named tuples. Due to the fact that all the query logic with marked fields is implemented in ValuesQuerySet
(returned from QuerySet.values()
), we just need to process the result before issuing: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()
and values_list()
accelerators. And it does it either better, or almost also and thus generates a more beautiful code. Maybe someday it will lead to their replacement.nametuples()
, scored on this for speed. Implementing the reordering of fields, if anyone needs it, can be taken from ValuesListQuerySet.iterator()
.Source: https://habr.com/ru/post/115797/
All Articles