1313from  django .db .models .lookups  import  IsNull 
1414from  django .db .models .sql  import  compiler 
1515from  django .db .models .sql .constants  import  GET_ITERATOR_CHUNK_SIZE , MULTI , SINGLE 
16+ from  django .db .models .sql .datastructures  import  BaseTable 
1617from  django .utils .functional  import  cached_property 
1718from  pymongo  import  ASCENDING , DESCENDING 
1819
@@ -25,12 +26,16 @@ class SQLCompiler(compiler.SQLCompiler):
2526
2627 query_class  =  MongoQuery 
2728 GROUP_SEPARATOR  =  "___" 
29+  PARENT_FIELD_TEMPLATE  =  "parent__field__{}" 
2830
2931 def  __init__ (self , * args , ** kwargs ):
3032 super ().__init__ (* args , ** kwargs )
3133 self .aggregation_pipeline  =  None 
34+  # Map columns to their subquery indices. 
35+  self .column_indices  =  {}
3236 # A list of OrderBy objects for this query. 
3337 self .order_by_objs  =  None 
38+  self .subqueries  =  []
3439
3540 def  _unfold_column (self , col ):
3641 """ 
@@ -154,23 +159,40 @@ def _prepare_annotations_for_aggregation_pipeline(self, order_by):
154159 group .update (having_group )
155160 return  group , replacements 
156161
157-  def  _get_group_id_expressions (self , order_by ):
158-  """Generate group ID expressions for the aggregation pipeline.""" 
159-  group_expressions  =  set ()
160-  replacements  =  {}
162+  def  _get_group_expressions (self , order_by ):
163+  if  self .query .group_by  is  None :
164+  return  []
165+  seen  =  set ()
166+  expressions  =  set ()
167+  if  self .query .group_by  is  not True :
168+  # If group_by isn't True, then it's a list of expressions. 
169+  for  expr  in  self .query .group_by :
170+  if  not  hasattr (expr , "as_sql" ):
171+  expr  =  self .query .resolve_ref (expr )
172+  if  isinstance (expr , Ref ):
173+  if  expr .refs  not  in seen :
174+  seen .add (expr .refs )
175+  expressions .add (expr .source )
176+  else :
177+  expressions .add (expr )
178+  for  expr , _ , alias  in  self .select :
179+  # Skip members that are already grouped. 
180+  if  alias  not  in seen :
181+  expressions  |=  set (expr .get_group_by_cols ())
161182 if  not  self ._meta_ordering :
162183 for  expr , (_ , _ , is_ref ) in  order_by :
184+  # Skip references. 
163185 if  not  is_ref :
164-  group_expressions  |=  set (expr .get_group_by_cols ())
165-  for  expr , * _  in  self .select :
166-  group_expressions  |=  set (expr .get_group_by_cols ())
186+  expressions  |=  set (expr .get_group_by_cols ())
167187 having_group_by  =  self .having .get_group_by_cols () if  self .having  else  ()
168188 for  expr  in  having_group_by :
169-  group_expressions .add (expr )
170-  if  isinstance (self .query .group_by , tuple  |  list ):
171-  group_expressions  |=  set (self .query .group_by )
172-  elif  self .query .group_by  is  None :
173-  group_expressions  =  set ()
189+  expressions .add (expr )
190+  return  expressions 
191+ 
192+  def  _get_group_id_expressions (self , order_by ):
193+  """Generate group ID expressions for the aggregation pipeline.""" 
194+  replacements  =  {}
195+  group_expressions  =  self ._get_group_expressions (order_by )
174196 if  not  group_expressions :
175197 ids  =  None 
176198 else :
@@ -186,6 +208,8 @@ def _get_group_id_expressions(self, order_by):
186208 ids [alias ] =  Value (True ).as_mql (self , self .connection )
187209 if  replacement  is  not None :
188210 replacements [col ] =  replacement 
211+  if  isinstance (col , Ref ):
212+  replacements [col .source ] =  replacement 
189213 return  ids , replacements 
190214
191215 def  _build_aggregation_pipeline (self , ids , group ):
@@ -228,15 +252,15 @@ def pre_sql_setup(self, with_col_aliases=False):
228252 all_replacements .update (replacements )
229253 pipeline  =  self ._build_aggregation_pipeline (ids , group )
230254 if  self .having :
231-  pipeline .append (
232-  {
233-  "$match" : {
234-  "$expr" : self .having .replace_expressions (all_replacements ).as_mql (
235-  self , self .connection 
236-  )
237-  }
238-  }
255+  having  =  self .having .replace_expressions (all_replacements ).as_mql (
256+  self , self .connection 
239257 )
258+  # Add HAVING subqueries. 
259+  for  query  in  self .subqueries  or  ():
260+  pipeline .extend (query .get_pipeline ())
261+  # Remove the added subqueries. 
262+  self .subqueries  =  []
263+  pipeline .append ({"$match" : {"$expr" : having }})
240264 self .aggregation_pipeline  =  pipeline 
241265 self .annotations  =  {
242266 target : expr .replace_expressions (all_replacements )
@@ -388,6 +412,7 @@ def build_query(self, columns=None):
388412 query .mongo_query  =  {"$expr" : expr }
389413 if  extra_fields :
390414 query .extra_fields  =  self .get_project_fields (extra_fields , force_expression = True )
415+  query .subqueries  =  self .subqueries 
391416 return  query 
392417
393418 def  get_columns (self ):
@@ -431,7 +456,12 @@ def project_field(column):
431456
432457 @cached_property  
433458 def  collection_name (self ):
434-  return  self .query .get_meta ().db_table 
459+  base_table  =  next (
460+  v 
461+  for  k , v  in  self .query .alias_map .items ()
462+  if  isinstance (v , BaseTable ) and  self .query .alias_refcount [k ]
463+  )
464+  return  base_table .table_alias  or  base_table .table_name 
435465
436466 @cached_property  
437467 def  collection (self ):
@@ -581,7 +611,7 @@ def _get_ordering(self):
581611 return  tuple (fields ), sort_ordering , tuple (extra_fields )
582612
583613 def  get_where (self ):
584-  return  self . where 
614+  return  getattr ( self ,  "where" ,  self . query . where ) 
585615
586616 def  explain_query (self ):
587617 # Validate format (none supported) and options. 
@@ -741,7 +771,7 @@ def build_query(self, columns=None):
741771 else  None 
742772 )
743773 subquery  =  compiler .build_query (columns )
744-  query .subquery  =  subquery 
774+  query .subqueries  =  [ subquery ] 
745775 return  query 
746776
747777 def  _make_result (self , result , columns = None ):
0 commit comments