Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.5.x] Optimisation in prefetch_related_objects

Backport of 17559e6 from master
  • Loading branch information...
commit a2eb2195567e645c58ec20c382294b62640b9ea1 1 parent 00b39e0
Luke Plant authored May 24, 2013 timgraham committed July 27, 2013

Showing 1 changed file with 22 additions and 25 deletions. Show diff stats Hide diff stats

  1. 47  django/db/models/query.py
47  django/db/models/query.py
@@ -1713,8 +1713,18 @@ def prefetch_related_objects(result_cache, related_lookups):
1713 1713
             if len(obj_list) == 0:
1714 1714
                 break
1715 1715
 
  1716
+            current_lookup = LOOKUP_SEP.join(attrs[0:level+1])
  1717
+            if current_lookup in done_queries:
  1718
+                # Skip any prefetching, and any object preparation
  1719
+                obj_list = done_queries[current_lookup]
  1720
+                continue
  1721
+
  1722
+            # Prepare objects:
1716 1723
             good_objects = True
1717 1724
             for obj in obj_list:
  1725
+                # Since prefetching can re-use instances, it is possible to have
  1726
+                # the same instance multiple times in obj_list, so obj might
  1727
+                # already be prepared.
1718 1728
                 if not hasattr(obj, '_prefetched_objects_cache'):
1719 1729
                     try:
1720 1730
                         obj._prefetched_objects_cache = {}
@@ -1725,14 +1735,6 @@ def prefetch_related_objects(result_cache, related_lookups):
1725 1735
                         # now.
1726 1736
                         good_objects = False
1727 1737
                         break
1728  
-                else:
1729  
-                    # Since prefetching can re-use instances, it is possible to
1730  
-                    # have the same instance multiple times in obj_list. So we
1731  
-                    # can reach this branch either because we did all of
1732  
-                    # obj_list already, or because we did 'obj' earlier in this
1733  
-                    # iteration over obj_list. In the first case we could
1734  
-                    # shortcut and exit the loop, but not in the second.
1735  
-                    continue
1736 1738
             if not good_objects:
1737 1739
                 break
1738 1740
 
@@ -1757,23 +1759,18 @@ def prefetch_related_objects(result_cache, related_lookups):
1757 1759
                                  "prefetch_related()." % lookup)
1758 1760
 
1759 1761
             if prefetcher is not None and not is_fetched:
1760  
-                # Check we didn't do this already
1761  
-                current_lookup = LOOKUP_SEP.join(attrs[0:level+1])
1762  
-                if current_lookup in done_queries:
1763  
-                    obj_list = done_queries[current_lookup]
1764  
-                else:
1765  
-                    obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr)
1766  
-                    # We need to ensure we don't keep adding lookups from the
1767  
-                    # same relationships to stop infinite recursion. So, if we
1768  
-                    # are already on an automatically added lookup, don't add
1769  
-                    # the new lookups from relationships we've seen already.
1770  
-                    if not (lookup in auto_lookups and
1771  
-                            descriptor in followed_descriptors):
1772  
-                        for f in additional_prl:
1773  
-                            new_prl = LOOKUP_SEP.join([current_lookup, f])
1774  
-                            auto_lookups.append(new_prl)
1775  
-                        done_queries[current_lookup] = obj_list
1776  
-                    followed_descriptors.add(descriptor)
  1762
+                obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr)
  1763
+                # We need to ensure we don't keep adding lookups from the
  1764
+                # same relationships to stop infinite recursion. So, if we
  1765
+                # are already on an automatically added lookup, don't add
  1766
+                # the new lookups from relationships we've seen already.
  1767
+                if not (lookup in auto_lookups and
  1768
+                        descriptor in followed_descriptors):
  1769
+                    for f in additional_prl:
  1770
+                        new_prl = LOOKUP_SEP.join([current_lookup, f])
  1771
+                        auto_lookups.append(new_prl)
  1772
+                    done_queries[current_lookup] = obj_list
  1773
+                followed_descriptors.add(descriptor)
1777 1774
             else:
1778 1775
                 # Either a singly related object that has already been fetched
1779 1776
                 # (e.g. via select_related), or hopefully some other property

0 notes on commit a2eb219

Please sign in to comment.
Something went wrong with that request. Please try again.