Ticket #16902: query.py.diff

File query.py.diff, 12.8 KB (added by ivan_virabyan, 4 years ago)
  • django/db/models/query.py

     
    265265        db = self.db
    266266        model = self.model
    267267        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)
    268271        for row in compiler.results_iter():
    269272            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))
    274275            else:
    275276                if skip:
    276277                    row_data = row[index_start:aggregate_start]
     
    11741175    # situations).
    11751176    value_annotation = False
    11761177
    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):
     1178def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None,
     1179                   only_load=None, local_only=False):
    11801180    """
    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   
    11871185    Arguments:
    11881186     * klass - the class to retrieve (and instantiate)
    1189      * row - the row of data returned by the database cursor
    1190      * index_start - the index of the row at which data for this
    1191        object is known to start
    1192      * using - the database alias on which the query is being executed.
    11931187     * max_depth - the maximum depth to which a select_related()
    11941188       relationship should be explored.
    11951189     * cur_depth - the current depth in the select_related() tree.
     
    11981192       that is to be retrieved. keys are field names; values are
    11991193       dictionaries describing the keys on that related object that
    12001194       are themselves to be select_related().
    1201      * offset - the number of additional fields that are known to
    1202        exist in `row` for `klass`. This usually means the number of
    1203        annotated results on `klass`.
    12041195     * only_load - if the query has had only() or defer() applied,
    12051196       this is the list of field names that will be returned. If None,
    12061197       the full field list for `klass` can be assumed.
     
    12101201    if max_depth and requested is None and cur_depth > max_depth:
    12111202        # We've recursed deeply enough; stop now.
    12121203        return None
    1213 
    1214     restricted = requested is not None
     1204   
    12151205    if only_load:
    12161206        load_fields = only_load.get(klass)
    12171207        # When we create the object, we will also be creating populating
     
    12231213                load_fields.update(fields)
    12241214    else:
    12251215        load_fields = None
     1216   
    12261217    if load_fields:
    12271218        # Handle deferred fields.
    12281219        skip = set()
     
    12371228                init_list.append(field.attname)
    12381229        # Retrieve all the requested fields
    12391230        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:
    12471232            klass = deferred_class_factory(klass, skip)
    1248             obj = klass(**dict(zip(init_list, fields)))
     1233            field_names = init_list
    12491234        else:
    1250             obj = klass(*fields)
    1251 
     1235            field_names = ()
    12521236    else:
    12531237        # 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)
    12551246            field_names = [f.attname for f in klass._meta.local_fields]
    12561247        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
     1276def 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)))
    12651307        else:
    1266             obj = klass(**dict(zip(field_names, fields)))
    1267 
     1308            obj = klass(*fields)
     1309   
    12681310    # If an object was retrieved, set the database state.
    12691311    if obj:
    12701312        obj._state.db = using
    12711313        obj._state.adding = False
    1272 
     1314   
     1315    # Instantiate related fields
    12731316    index_end = index_start + field_count + offset
    12741317    # Iterate over each related object, populating any
    12751318    # 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:
    12831320        # 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)
    12861322        # If the recursive descent found an object, populate the
    12871323        # descriptor caches relevant to the object
    12881324        if cached_row:
     
    12991335    # Now do the same, but for reverse related objects.
    13001336    # Only handle the restricted case - i.e., don't do a depth
    13011337    # 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
    13411367    return obj, index_end
    13421368
    13431369
Back to Top