11from functools import reduce , wraps
2+ from itertools import chain
23from operator import add as add_operator
34
45from django .core .exceptions import EmptyResultSet , FieldDoesNotExist , FullResultSet
@@ -387,11 +388,17 @@ def __iter__(self):
387388 query = self .queryset .query
388389 connection = connections [db ]
389390 compiler = connection .ops .compiler ("SQLCompiler" )(query , connection , db )
390- query_iterator = self ._make_result (query )
391- # FIXME Get columns from first row of the query without iterating over
392- # the query.
393- columns = self .queryset .columns
394-
391+ query_iterator = iter (query )
392+ # Get the columns from the first result.
393+ try :
394+ first_item = next (query_iterator )
395+ except StopIteration :
396+ # No results.
397+ query .cursor .close ()
398+ return
399+ columns = list (first_item .keys ())
400+ # Reset the iterator to include the first item.
401+ query_iterator = self ._make_result (chain ([first_item ], query_iterator ))
395402 try :
396403 (
397404 model_init_names ,
@@ -401,7 +408,7 @@ def __iter__(self):
401408 model_cls = self .queryset .model
402409 if model_cls ._meta .pk .attname not in model_init_names :
403410 raise FieldDoesNotExist ("Raw query must include the primary key" )
404- fields = [self .queryset .model_fields .get (c ) for c in self . queryset . columns ]
411+ fields = [self .queryset .model_fields .get (c ) for c in columns ]
405412 converters = compiler .get_converters (
406413 [f .get_col (f .model ._meta .db_table ) if f else None for f in fields ]
407414 )
0 commit comments