Ticket #17014: prefetch_recursion_trunk.diff
File prefetch_recursion_trunk.diff, 4.6 KB (added by , 13 years ago) |
---|
-
django/db/models/query.py
diff --git a/django/db/models/query.py b/django/db/models/query.py index b21db2e..cb79382 100644
a b REPR_OUTPUT_SIZE = 20 23 23 # Pull into this namespace for backwards compatibility. 24 24 EmptyResultSet = sql.EmptyResultSet 25 25 26 # Maximum amount of prefetch related queries to be done when evaluating 27 # a single queryset. 28 MAX_PREFETCH_PER_QUERY = 100 29 26 30 class QuerySet(object): 27 31 """ 28 32 Represents a lazy database lookup for a set of objects. … … def prefetch_related_objects(result_cache, related_lookups): 1578 1582 1579 1583 # We may expand related_lookups, so need a loop that allows for that 1580 1584 for lookup in related_lookups: 1585 if len(done_queries) > MAX_PREFETCH_PER_QUERY: 1586 raise ValueError( 1587 'Over %s prefetch_related lookups in one query. ' 1588 'Likely reason is recursion caused by default managers' 1589 % MAX_PREFETCH_PER_QUERY 1590 ) 1581 1591 if lookup in done_lookups: 1582 1592 # We've done exactly this already, skip the whole thing 1583 1593 continue -
tests/modeltests/prefetch_related/models.py
diff --git a/tests/modeltests/prefetch_related/models.py b/tests/modeltests/prefetch_related/models.py index ab28496..8ea01a0 100644
a b class Employee(models.Model): 163 163 164 164 class Meta: 165 165 ordering = ['id'] 166 167 class RecursiveManager(models.Manager): 168 def get_query_set(self): 169 return (super(RecursiveManager, self).get_query_set() 170 .prefetch_related('recurse_reverse')) 171 172 class RecursiveRel(models.Model): 173 val = models.TextField() 174 recursion = models.ForeignKey('self', related_name='recurse_reverse', null=True) 175 objects = RecursiveManager() 176 177 """ 178 Construct a nasty diamond strucure of models, 179 connected by default managers: 180 B 181 / \ 182 / \ 183 / \ 184 A <---- D 185 \ / 186 \ / 187 \ / 188 C 189 190 Contains two loops: 191 A -> C -> D -> A 192 A -> B -> D -> A 193 194 In addition, C -> D and B -> D have same accessor name, d_set 195 """ 196 197 class AManager(models.Manager): 198 def get_query_set(self): 199 return super(AManager, self).get_query_set().prefetch_related('b_set', 'c_set') 200 201 class BManager(models.Manager): 202 def get_query_set(self): 203 return super(BManager, self).get_query_set().prefetch_related('d_set') 204 205 class CManager(models.Manager): 206 def get_query_set(self): 207 return super(CManager, self).get_query_set().prefetch_related('d_set') 208 209 class DManager(models.Manager): 210 def get_query_set(self): 211 return super(CManager, self).get_query_set().prefetch_related('a_set') 212 213 class DiamondA(models.Model): 214 d = models.ForeignKey('DiamondD', null=True) 215 objects = AManager() 216 217 class DiamondB(models.Model): 218 a = models.ForeignKey(DiamondA, null=True) 219 objects = BManager() 220 221 class DiamondC(models.Model): 222 a = models.ForeignKey(DiamondA, null=True) 223 objects = CManager() 224 225 class DiamondD(models.Model): 226 b = models.ForeignKey(DiamondB, null=True) 227 c = models.ForeignKey(DiamondC, null=True) 228 objects = DManager() -
tests/modeltests/prefetch_related/tests.py
diff --git a/tests/modeltests/prefetch_related/tests.py b/tests/modeltests/prefetch_related/tests.py index 45202f2..c991fc3 100644
a b from django.utils import unittest 7 7 from models import (Author, Book, Reader, Qualification, Teacher, Department, 8 8 TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, 9 9 AuthorWithAge, BookWithYear, Person, House, Room, 10 Employee) 10 Employee, RecursiveRel, DiamondA, DiamondB, DiamondC, 11 DiamondD) 11 12 12 13 13 14 class PrefetchRelatedTests(TestCase): … … class NullableTest(TestCase): 416 417 for e in qs2] 417 418 418 419 self.assertEqual(co_serfs, co_serfs2) 420 421 422 class RecursionTest(TestCase): 423 def setUp(self): 424 r1 = RecursiveRel.objects.create(val='foo') 425 r2 = RecursiveRel.objects.create(val='foo', recursion=r1) 426 r1.recursion = r2 427 r1.save() 428 429 def test_recursion(self): 430 RecursiveRel.objects.all()[0] 431 432 class DiamondTest(TestCase): 433 def setUp(self): 434 a = DiamondA.objects.create() 435 b = DiamondB.objects.create(a=a) 436 c = DiamondA.objects.create(a=a) 437 d = DiamondA.objects.create(b=b, c=c) 438 a.d = d 439 a.save() 440 441 def test_diamond_recusion(self): 442 DiamondA.objects.all()[0]