diff --git a/django/db/models/query.py b/django/db/models/query.py index f96e91e55c..a1a2428651 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -294,7 +294,8 @@ class _QuerySet(object): """Returns a new QuerySet instance that will select related objects.""" obj = self._clone() obj.query.select_related = true_or_false - obj.query.max_depth = depth + if depth: + obj.query.max_depth = depth return obj def order_by(self, *field_names): diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index f11da3be29..c633b8849f 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -87,7 +87,10 @@ class Query(object): self.low_mark, self.high_mark = 0, None # Used for offset/limit self.distinct = False self.select_related = False - self.max_depth = 0 + + # Arbitrary maximum limit for select_related to prevent infinite + # recursion. Can be changed by the depth parameter to select_related(). + self.max_depth = 5 # These are for extensions. The contents are more or less appended # verbatim to the appropriate clause. diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index 8c47e623d7..eb8595ecab 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -80,6 +80,14 @@ class Cover(models.Model): def __unicode__(self): return self.title +# Some funky cross-linked models for testing a couple of infinite recursion +# cases. +class X(models.Model): + y = models.ForeignKey('Y') + +class Y(models.Model): + x1 = models.ForeignKey(X, related_name='y1') + __test__ = {'API_TESTS':""" >>> t1 = Tag(name='t1') >>> t1.save() @@ -353,9 +361,18 @@ True >>> ExtraInfo.objects.values('note') [{'note': 1}, {'note': 2}] -# Bug 5261 +Bug #5261 >>> Note.objects.exclude(Q()) [, , ] +Bug #3045, #3288 +Once upon a time, select_related() with circular relations would loop +infinitely if you forgot to specify "depth". Now we set an arbitrary default +upper bound. +>>> X.objects.all() +[] +>>> X.objects.select_related() +[] + """}