#27554: Queryset evaluation fails with mix of nested and flattened prefetches
(AttributeError on RelatedManager)
-------------------------------------+-------------------------------------
Reporter: Anthony | Owner: nobody
Leontiev |
Type: Bug | Status: new
Component: Database | Version: 1.10
layer (models, ORM) | Keywords: prefetch
Severity: Normal | AttributeError prefetch_related
Triage Stage: | nested RelatedManager
Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Under certain circumstances, querysets with nested prefetches fail to
evaluate in Django 1.10.
With these models (populated with data):
{{{
# A <-> B <-- C --> D
# \__________/
class A(models.Model):
pass
class B(models.Model):
a = models.OneToOneField('A', null=True, related_name='b')
d = models.ManyToManyField('D', through='C', related_name='b')
class C(models.Model):
b = models.ForeignKey('B', related_name='c')
d = models.ForeignKey('D', related_name='c')
class D(models.Model):
pass
}}}
... and this query/evaluation:
{{{
queryset = A.objects.all().prefetch_related(
Prefetch(
'b',
queryset=B.objects.all().prefetch_related(
Prefetch('c__d')
)
)
)
content = queryset[0].b.c.all()[0].d.pk
}}}
Django throws this exception:
{{{
File "/Users/ant/code/django-bugs/prefetchbug/.venv/lib/python2.7/site-
packages/django/db/models/query.py", line 256, in __iter__
self._fetch_all()
File "/Users/ant/code/django-bugs/prefetchbug/.venv/lib/python2.7/site-
packages/django/db/models/query.py", line 1087, in _fetch_all
self._prefetch_related_objects()
File "/Users/ant/code/django-bugs/prefetchbug/.venv/lib/python2.7/site-
packages/django/db/models/query.py", line 663, in
_prefetch_related_objects
prefetch_related_objects(self._result_cache,
*self._prefetch_related_lookups)
File "/Users/ant/code/django-bugs/prefetchbug/.venv/lib/python2.7/site-
packages/django/db/models/query.py", line 1460, in
prefetch_related_objects
(through_attr, first_obj.__class__.__name__, lookup.prefetch_through))
AttributeError: Cannot find 'd' on RelatedManager object, 'b__c__d' is an
invalid parameter to prefetch_related()
}}}
Interestingly enough, this practically identical variant of the above
query with a fully "nested" prefetch structure succeeds:
{{{
queryset = A.objects.all().prefetch_related(
Prefetch(
'b',
queryset=B.objects.all().prefetch_related(
Prefetch(
'c',
queryset=C.objects.all().prefetch_related(
'd'
)
)
)
)
)
content = queryset[0].b.c.all()[0].d.pk
}}}
To reproduce, download the attachment and run:
{{{
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver
}}}
... and navigate to {localhost:8000/flat} and {localhost:8000/nested}.
This only seems to impact Django 1.10; the bug does not reproduce if the
Django version in the {requirements.txt} file is changed to 1.9 or 1.8.
Discovered in https://github.com/AltSchool/dynamic-rest/pull/147
Similar to https://code.djangoproject.com/ticket/26801
--
Ticket URL: <https://code.djangoproject.com/ticket/27554>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/052.bf8ec19593cd94e61162767dd14fa0ca%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.