1
0
mirror of https://github.com/django/django.git synced 2025-05-10 00:46:28 +00:00

[1.5.x] Optimisation in prefetch_related_objects

Backport of 17559e6eb0 from master
This commit is contained in:
Luke Plant 2013-05-24 11:19:44 +01:00 committed by Tim Graham
parent 00b39e0145
commit a2eb219556

View File

@ -1713,8 +1713,18 @@ def prefetch_related_objects(result_cache, related_lookups):
if len(obj_list) == 0: if len(obj_list) == 0:
break break
current_lookup = LOOKUP_SEP.join(attrs[0:level+1])
if current_lookup in done_queries:
# Skip any prefetching, and any object preparation
obj_list = done_queries[current_lookup]
continue
# Prepare objects:
good_objects = True good_objects = True
for obj in obj_list: for obj in obj_list:
# Since prefetching can re-use instances, it is possible to have
# the same instance multiple times in obj_list, so obj might
# already be prepared.
if not hasattr(obj, '_prefetched_objects_cache'): if not hasattr(obj, '_prefetched_objects_cache'):
try: try:
obj._prefetched_objects_cache = {} obj._prefetched_objects_cache = {}
@ -1725,14 +1735,6 @@ def prefetch_related_objects(result_cache, related_lookups):
# now. # now.
good_objects = False good_objects = False
break break
else:
# Since prefetching can re-use instances, it is possible to
# have the same instance multiple times in obj_list. So we
# can reach this branch either because we did all of
# obj_list already, or because we did 'obj' earlier in this
# iteration over obj_list. In the first case we could
# shortcut and exit the loop, but not in the second.
continue
if not good_objects: if not good_objects:
break break
@ -1757,23 +1759,18 @@ def prefetch_related_objects(result_cache, related_lookups):
"prefetch_related()." % lookup) "prefetch_related()." % lookup)
if prefetcher is not None and not is_fetched: if prefetcher is not None and not is_fetched:
# Check we didn't do this already obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr)
current_lookup = LOOKUP_SEP.join(attrs[0:level+1]) # We need to ensure we don't keep adding lookups from the
if current_lookup in done_queries: # same relationships to stop infinite recursion. So, if we
obj_list = done_queries[current_lookup] # are already on an automatically added lookup, don't add
else: # the new lookups from relationships we've seen already.
obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr) if not (lookup in auto_lookups and
# We need to ensure we don't keep adding lookups from the descriptor in followed_descriptors):
# same relationships to stop infinite recursion. So, if we for f in additional_prl:
# are already on an automatically added lookup, don't add new_prl = LOOKUP_SEP.join([current_lookup, f])
# the new lookups from relationships we've seen already. auto_lookups.append(new_prl)
if not (lookup in auto_lookups and done_queries[current_lookup] = obj_list
descriptor in followed_descriptors): followed_descriptors.add(descriptor)
for f in additional_prl:
new_prl = LOOKUP_SEP.join([current_lookup, f])
auto_lookups.append(new_prl)
done_queries[current_lookup] = obj_list
followed_descriptors.add(descriptor)
else: else:
# Either a singly related object that has already been fetched # Either a singly related object that has already been fetched
# (e.g. via select_related), or hopefully some other property # (e.g. via select_related), or hopefully some other property