1
1
from django .core .exceptions import EmptyResultSet , FieldDoesNotExist , FullResultSet
2
2
from django .db import DatabaseError , IntegrityError , NotSupportedError
3
- from django .db .models import NOT_PROVIDED , Count , Expression
3
+ from django .db .models import Count , Expression
4
4
from django .db .models .aggregates import Aggregate
5
5
from django .db .models .constants import LOOKUP_SEP
6
6
from django .db .models .sql import compiler
@@ -23,14 +23,21 @@ def execute_sql(
23
23
# QuerySet.count()
24
24
if self .query .annotations == {"__count" : Count ("*" )}:
25
25
return [self .get_count ()]
26
- # Specify columns if there are any annotations so that annotations are
27
- # computed via $project.
28
- columns = self .get_columns () if self .query .annotations else None
26
+
27
+ columns = self .get_columns ()
29
28
try :
30
- query = self .build_query (columns )
29
+ query = self .build_query (
30
+ # Avoid $project (columns=None) if unneeded.
31
+ columns if self .query .annotations or not self .query .default_cols else None
32
+ )
31
33
except EmptyResultSet :
32
- return None
33
- return query .fetch ()
34
+ return iter ([]) if result_type == MULTI else None
35
+
36
+ return (
37
+ (self ._make_result (row , columns ) for row in query .fetch ())
38
+ if result_type == MULTI
39
+ else self ._make_result (next (query .fetch ()), columns )
40
+ )
34
41
35
42
def results_iter (
36
43
self ,
@@ -43,37 +50,23 @@ def results_iter(
43
50
Return an iterator over the results from executing query given
44
51
to this compiler. Called by QuerySet methods.
45
52
"""
46
- columns = self .get_columns ()
47
-
48
53
if results is None :
49
54
# QuerySet.values() or values_list()
50
- try :
51
- results = self .build_query (columns ).fetch ()
52
- except EmptyResultSet :
53
- results = []
55
+ results = self .execute_sql (MULTI , chunked_fetch = chunked_fetch , chunk_size = chunk_size )
54
56
55
- converters = self .get_converters (columns )
56
- for entity in results :
57
- yield self ._make_result (entity , columns , converters , tuple_expected = tuple_expected )
57
+ fields = [s [0 ] for s in self .select [0 : self .col_count ]]
58
+ converters = self .get_converters (fields )
59
+ rows = results
60
+ if converters :
61
+ rows = self .apply_converters (rows , converters )
62
+ if tuple_expected :
63
+ rows = map (tuple , rows )
64
+ return rows
58
65
59
66
def has_results (self ):
60
67
return bool (self .get_count (check_exists = True ))
61
68
62
- def get_converters (self , expressions ):
63
- converters = {}
64
- for name_expr in expressions :
65
- try :
66
- name , expr = name_expr
67
- except TypeError :
68
- # e.g., Count("*")
69
- continue
70
- backend_converters = self .connection .ops .get_db_converters (expr )
71
- field_converters = expr .get_db_converters (self .connection )
72
- if backend_converters or field_converters :
73
- converters [name ] = backend_converters + field_converters
74
- return converters
75
-
76
- def _make_result (self , entity , columns , converters , tuple_expected = False ):
69
+ def _make_result (self , entity , columns ):
77
70
"""
78
71
Decode values for the given fields from the database entity.
79
72
@@ -82,7 +75,6 @@ def _make_result(self, entity, columns, converters, tuple_expected=False):
82
75
"""
83
76
result = []
84
77
for name , col in columns :
85
- field = col .field
86
78
column_alias = getattr (col , "alias" , None )
87
79
obj = (
88
80
# Use the related object...
@@ -91,16 +83,7 @@ def _make_result(self, entity, columns, converters, tuple_expected=False):
91
83
if column_alias is not None and column_alias != self .collection_name
92
84
else entity
93
85
)
94
- value = obj .get (name , NOT_PROVIDED )
95
- if value is NOT_PROVIDED :
96
- value = field .get_default ()
97
- elif converters :
98
- # Decode values using Django's database converters API.
99
- for converter in converters .get (name , ()):
100
- value = converter (value , col , self .connection )
101
- result .append (value )
102
- if tuple_expected :
103
- result = tuple (result )
86
+ result .append (obj .get (name , col .field .get_default ()))
104
87
return result
105
88
106
89
def check_query (self ):
0 commit comments