Ticket #16902: query.py.diff
File query.py.diff, 12.8 KB (added by , 13 years ago) |
---|
-
django/db/models/query.py
265 265 db = self.db 266 266 model = self.model 267 267 compiler = self.query.get_compiler(using=db) 268 if fill_cache: 269 klass_info = get_klass_info(model, max_depth=max_depth, 270 requested=requested, only_load=only_load) 268 271 for row in compiler.results_iter(): 269 272 if fill_cache: 270 obj, _ = get_cached_row(model, row, 271 index_start, using=db, max_depth=max_depth, 272 requested=requested, offset=len(aggregate_select), 273 only_load=only_load) 273 obj, _ = get_cached_row(row, index_start, db, klass_info, 274 offset=len(aggregate_select)) 274 275 else: 275 276 if skip: 276 277 row_data = row[index_start:aggregate_start] … … 1174 1175 # situations). 1175 1176 value_annotation = False 1176 1177 1177 1178 def get_cached_row(klass, row, index_start, using, max_depth=0, cur_depth=0, 1179 requested=None, offset=0, only_load=None, local_only=False): 1178 def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None, 1179 only_load=None, local_only=False): 1180 1180 """ 1181 Helper function that recursively returns an object with the specified 1182 related attributes already populated. 1183 1184 This method may be called recursively to populate deep select_related() 1185 clauses. 1186 1181 Helper function that recursively returns an information for a klass, to be used in get_cached_row. 1182 It exists just to compute this information only once for entire queryset. Otherwise it would be 1183 computed for each row, which leads to poor perfomance on large querysets. 1184 1187 1185 Arguments: 1188 1186 * klass - the class to retrieve (and instantiate) 1189 * row - the row of data returned by the database cursor1190 * index_start - the index of the row at which data for this1191 object is known to start1192 * using - the database alias on which the query is being executed.1193 1187 * max_depth - the maximum depth to which a select_related() 1194 1188 relationship should be explored. 1195 1189 * cur_depth - the current depth in the select_related() tree. … … 1198 1192 that is to be retrieved. keys are field names; values are 1199 1193 dictionaries describing the keys on that related object that 1200 1194 are themselves to be select_related(). 1201 * offset - the number of additional fields that are known to1202 exist in `row` for `klass`. This usually means the number of1203 annotated results on `klass`.1204 1195 * only_load - if the query has had only() or defer() applied, 1205 1196 this is the list of field names that will be returned. If None, 1206 1197 the full field list for `klass` can be assumed. … … 1210 1201 if max_depth and requested is None and cur_depth > max_depth: 1211 1202 # We've recursed deeply enough; stop now. 1212 1203 return None 1213 1214 restricted = requested is not None 1204 1215 1205 if only_load: 1216 1206 load_fields = only_load.get(klass) 1217 1207 # When we create the object, we will also be creating populating … … 1223 1213 load_fields.update(fields) 1224 1214 else: 1225 1215 load_fields = None 1216 1226 1217 if load_fields: 1227 1218 # Handle deferred fields. 1228 1219 skip = set() … … 1237 1228 init_list.append(field.attname) 1238 1229 # Retrieve all the requested fields 1239 1230 field_count = len(init_list) 1240 fields = row[index_start : index_start + field_count] 1241 # If all the select_related columns are None, then the related 1242 # object must be non-existent - set the relation to None. 1243 # Otherwise, construct the related object. 1244 if fields == (None,) * field_count: 1245 obj = None 1246 elif skip: 1231 if skip: 1247 1232 klass = deferred_class_factory(klass, skip) 1248 obj = klass(**dict(zip(init_list, fields)))1233 field_names = init_list 1249 1234 else: 1250 obj = klass(*fields) 1251 1235 field_names = () 1252 1236 else: 1253 1237 # Load all fields on klass 1254 if local_only: 1238 1239 # We trying to not populate field_names variable for perfomance reason. 1240 # If field_names variable is set, it is used to instantiate desired fields, 1241 # by passing **dict(zip(field_names, fields)) as kwargs to Model.__init__ method. 1242 # But kwargs version of Model.__init__ is slower, so we should avoid using 1243 # it when it is not really neccesary. 1244 if local_only and len(klass._meta.local_fields) != len(klass._meta.fields): 1245 field_count = len(klass._meta.local_fields) 1255 1246 field_names = [f.attname for f in klass._meta.local_fields] 1256 1247 else: 1257 field_names = [f.attname for f in klass._meta.fields] 1258 field_count = len(field_names) 1259 fields = row[index_start : index_start + field_count] 1260 # If all the select_related columns are None, then the related 1261 # object must be non-existent - set the relation to None. 1262 # Otherwise, construct the related object. 1263 if fields == (None,) * field_count: 1264 obj = None 1248 field_count = len(klass._meta.fields) 1249 field_names = () 1250 1251 restricted = requested is not None 1252 1253 related_fields = [] 1254 for f in klass._meta.fields: 1255 if select_related_descend(f, restricted, requested): 1256 if restricted: 1257 next = requested[f.name] 1258 else: 1259 next = None 1260 klass_info = get_klass_info(f.rel.to, max_depth, cur_depth+1, 1261 next, only_load=only_load) 1262 related_fields.append((f, klass_info)) 1263 1264 reverse_related_fields = [] 1265 if restricted: 1266 for o in klass._meta.get_all_related_objects(): 1267 if o.field.unique and select_related_descend(o.field, restricted, requested, reverse=True): 1268 next = requested[o.field.related_query_name()] 1269 klass_info = get_klass_info(o.model, max_depth, cur_depth+1, next, 1270 only_load=only_load, local_only=True) 1271 reverse_related_fields.append((o.field, klass_info)) 1272 1273 return klass, field_names, field_count, related_fields, reverse_related_fields 1274 1275 1276 def get_cached_row(row, index_start, using, klass_info, offset=0): 1277 """ 1278 Helper function that recursively returns an object with the specified 1279 related attributes already populated. 1280 1281 This method may be called recursively to populate deep select_related() 1282 clauses. 1283 1284 Arguments: 1285 * row - the row of data returned by the database cursor 1286 * index_start - the index of the row at which data for this 1287 object is known to start 1288 * offset - the number of additional fields that are known to 1289 exist in row for `klass`. This usually means the number of 1290 annotated results on `klass`. 1291 * using - the database alias on which the query is being executed. 1292 * klass_info - result of the get_klass_info function 1293 """ 1294 if klass_info is None: 1295 return None 1296 klass, field_names, field_count, related_fields, reverse_related_fields = klass_info 1297 1298 fields = row[index_start : index_start + field_count] 1299 # If all the select_related columns are None, then the related 1300 # object must be non-existent - set the relation to None. 1301 # Otherwise, construct the related object. 1302 if fields == (None,) * field_count: 1303 obj = None 1304 else: 1305 if field_names: 1306 obj = klass(**dict(zip(field_names, fields))) 1265 1307 else: 1266 obj = klass(* *dict(zip(field_names, fields)))1267 1308 obj = klass(*fields) 1309 1268 1310 # If an object was retrieved, set the database state. 1269 1311 if obj: 1270 1312 obj._state.db = using 1271 1313 obj._state.adding = False 1272 1314 1315 # Instantiate related fields 1273 1316 index_end = index_start + field_count + offset 1274 1317 # Iterate over each related object, populating any 1275 1318 # select_related() fields 1276 for f in klass._meta.fields: 1277 if not select_related_descend(f, restricted, requested): 1278 continue 1279 if restricted: 1280 next = requested[f.name] 1281 else: 1282 next = None 1319 for f, klass_info in related_fields: 1283 1320 # Recursively retrieve the data for the related object 1284 cached_row = get_cached_row(f.rel.to, row, index_end, using, 1285 max_depth, cur_depth+1, next, only_load=only_load) 1321 cached_row = get_cached_row(row, index_end, using, klass_info) 1286 1322 # If the recursive descent found an object, populate the 1287 1323 # descriptor caches relevant to the object 1288 1324 if cached_row: … … 1299 1335 # Now do the same, but for reverse related objects. 1300 1336 # Only handle the restricted case - i.e., don't do a depth 1301 1337 # descent into reverse relations unless explicitly requested 1302 if restricted: 1303 related_fields = [ 1304 (o.field, o.model) 1305 for o in klass._meta.get_all_related_objects() 1306 if o.field.unique 1307 ] 1308 for f, model in related_fields: 1309 if not select_related_descend(f, restricted, requested, reverse=True): 1310 continue 1311 next = requested[f.related_query_name()] 1312 # Recursively retrieve the data for the related object 1313 cached_row = get_cached_row(model, row, index_end, using, 1314 max_depth, cur_depth+1, next, only_load=only_load, local_only=True) 1315 # If the recursive descent found an object, populate the 1316 # descriptor caches relevant to the object 1317 if cached_row: 1318 rel_obj, index_end = cached_row 1319 if obj is not None: 1320 # If the field is unique, populate the 1321 # reverse descriptor cache 1322 setattr(obj, f.related.get_cache_name(), rel_obj) 1323 if rel_obj is not None: 1324 # If the related object exists, populate 1325 # the descriptor cache. 1326 setattr(rel_obj, f.get_cache_name(), obj) 1327 # Now populate all the non-local field values 1328 # on the related object 1329 for rel_field,rel_model in rel_obj._meta.get_fields_with_model(): 1330 if rel_model is not None: 1331 setattr(rel_obj, rel_field.attname, getattr(obj, rel_field.attname)) 1332 # populate the field cache for any related object 1333 # that has already been retrieved 1334 if rel_field.rel: 1335 try: 1336 cached_obj = getattr(obj, rel_field.get_cache_name()) 1337 setattr(rel_obj, rel_field.get_cache_name(), cached_obj) 1338 except AttributeError: 1339 # Related object hasn't been cached yet 1340 pass 1338 for f, klass_info in reverse_related_fields: 1339 # Recursively retrieve the data for the related object 1340 cached_row = get_cached_row(row, index_end, using, klass_info) 1341 # If the recursive descent found an object, populate the 1342 # descriptor caches relevant to the object 1343 if cached_row: 1344 rel_obj, index_end = cached_row 1345 if obj is not None: 1346 # If the field is unique, populate the 1347 # reverse descriptor cache 1348 setattr(obj, f.related.get_cache_name(), rel_obj) 1349 if rel_obj is not None: 1350 # If the related object exists, populate 1351 # the descriptor cache. 1352 setattr(rel_obj, f.get_cache_name(), obj) 1353 # Now populate all the non-local field values 1354 # on the related object 1355 for rel_field, rel_model in rel_obj._meta.get_fields_with_model(): 1356 if rel_model is not None: 1357 setattr(rel_obj, rel_field.attname, getattr(obj, rel_field.attname)) 1358 # populate the field cache for any related object 1359 # that has already been retrieved 1360 if rel_field.rel: 1361 try: 1362 cached_obj = getattr(obj, rel_field.get_cache_name()) 1363 setattr(rel_obj, rel_field.get_cache_name(), cached_obj) 1364 except AttributeError: 1365 # Related object hasn't been cached yet 1366 pass 1341 1367 return obj, index_end 1342 1368 1343 1369