Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #8106 -- Untangled some problems with complex select_related() …

…queries

and models that have multiple paths to them from other models.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8559 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 3deff41a32637f22aa393d5b10bdc43f5911d95e 1 parent 6abe046
Malcolm Tredinnick authored
21  django/db/models/sql/query.py
@@ -913,7 +913,7 @@ def join(self, connection, always_create=False, exclusions=(),
913 913
 
914 914
     def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
915 915
             used=None, requested=None, restricted=None, nullable=None,
916  
-            dupe_set=None):
  916
+            dupe_set=None, avoid_set=None):
917 917
         """
918 918
         Fill in the information needed for a select_related query. The current
919 919
         depth is measured as the number of connections away from the root model
@@ -933,8 +933,9 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
933 933
             used = set()
934 934
         if dupe_set is None:
935 935
             dupe_set = set()
  936
+        if avoid_set is None:
  937
+            avoid_set = set()
936 938
         orig_dupe_set = dupe_set
937  
-        orig_used = used
938 939
 
939 940
         # Setup for the case when only particular related fields should be
940 941
         # included in the related selection.
@@ -948,8 +949,12 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
948 949
         for f, model in opts.get_fields_with_model():
949 950
             if not select_related_descend(f, restricted, requested):
950 951
                 continue
  952
+            # The "avoid" set is aliases we want to avoid just for this
  953
+            # particular branch of the recursion. They aren't permanently
  954
+            # forbidden from reuse in the related selection tables (which is
  955
+            # what "used" specifies).
  956
+            avoid = avoid_set.copy()
951 957
             dupe_set = orig_dupe_set.copy()
952  
-            used = orig_used.copy()
953 958
             table = f.rel.to._meta.db_table
954 959
             if nullable or f.null:
955 960
                 promote = True
@@ -962,7 +967,7 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
962 967
                     lhs_col = int_opts.parents[int_model].column
963 968
                     dedupe = lhs_col in opts.duplicate_targets
964 969
                     if dedupe:
965  
-                        used.update(self.dupe_avoidance.get(id(opts), lhs_col),
  970
+                        avoid.update(self.dupe_avoidance.get(id(opts), lhs_col),
966 971
                                 ())
967 972
                         dupe_set.add((opts, lhs_col))
968 973
                     int_opts = int_model._meta
@@ -976,13 +981,13 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
976 981
 
977 982
             dedupe = f.column in opts.duplicate_targets
978 983
             if dupe_set or dedupe:
979  
-                used.update(self.dupe_avoidance.get((id(opts), f.column), ()))
  984
+                avoid.update(self.dupe_avoidance.get((id(opts), f.column), ()))
980 985
                 if dedupe:
981 986
                     dupe_set.add((opts, f.column))
982 987
 
983 988
             alias = self.join((alias, table, f.column,
984  
-                    f.rel.get_related_field().column), exclusions=used,
985  
-                    promote=promote)
  989
+                    f.rel.get_related_field().column),
  990
+                    exclusions=used.union(avoid), promote=promote)
986 991
             used.add(alias)
987 992
             self.related_select_cols.extend(self.get_default_columns(
988 993
                 start_alias=alias, opts=f.rel.to._meta, as_pairs=True)[0])
@@ -998,7 +1003,7 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
998 1003
             for dupe_opts, dupe_col in dupe_set:
999 1004
                 self.update_dupe_avoidance(dupe_opts, dupe_col, alias)
1000 1005
             self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
1001  
-                    used, next, restricted, new_nullable, dupe_set)
  1006
+                    used, next, restricted, new_nullable, dupe_set, avoid)
1002 1007
 
1003 1008
     def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
1004 1009
             can_reuse=None):
45  tests/regressiontests/select_related_regress/models.py
@@ -28,11 +28,35 @@ class Connection(models.Model):
@@ -57,4 +81,23 @@ def __unicode__(self):

0 notes on commit 3deff41

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