#16409: `defer()` and `only()` don't play nice with `annotate()`
-------------------------------------+-------------------------------------
 Reporter:  mrmachine                |          Owner:  nobody
     Type:  Bug                      |         Status:  new
Milestone:  1.4                      |      Component:  Database layer
  Version:  SVN                      |  (models, ORM)
 Keywords:  annotate defer only      |       Severity:  Normal
  count                              |   Triage Stage:  Unreviewed
Has patch:  0                        |  Easy pickings:  0
    UI/UX:  0                        |
-------------------------------------+-------------------------------------
 When adding `defer()` or `only()` to an existing query that used
 `annotate()` to cut out some fields, I started getting IndexError
 exceptions.

 At first, I thought it was due to `aggregate_start` not being reduced by
 the number of deferred fields in `QuerySet.iterator()`, but when I looked
 at the SQL being generated I saw that ALL fields were being dropped from
 the query, except for the annotation. I suspect that even if this is
 fixed, `aggregate_start` will also need to be reduced by the number of
 deferred fields.

 Here's the traceback:

 {{{
 >>> from django.db.models import Count
 >>> from django.contrib.auth.models import *
 >>> from django.contrib.admin.models import *
 >>> User.objects.annotate(Count('logentry'))
 [<User: manager>, <User: trak:1:10>, <User: admin>, <User: trak:3:5>,
 <User: trak:1:24>, <User: trak:3:9>, <User: trak:1:3>, <User: trak:4:11>,
 <User: trak:5:21>, <User: trak:1:14>, <User: trak:1:15>, <User: trak:1:2>,
 <User: trak:4:18>, <User: trak:4:19>, <User: trak:5:17>, <User: trak:3:6>,
 <User: trak:1:23>, <User: trak:3:16>, <User: trak:5:22>, <User:
 trak:4:12>, '...(remaining elements truncated)...']
 >>> User.objects.annotate(Count('logentry')).defer('first_name')
 Traceback (most recent call last):
   File "<console>", line 1, in <module>
   File "/Users/mrmachine/myproject/django/db/models/query.py", line 69, in
 __repr__
     data = list(self[:REPR_OUTPUT_SIZE + 1])
   File "/Users/mrmachine/myproject/django/db/models/query.py", line 84, in
 __len__
     self._result_cache.extend(self._iter)
   File "/Users/mrmachine/myproject/django/db/models/query.py", line 300,
 in iterator
     setattr(obj, aggregate, row[i+aggregate_start])
 IndexError: tuple index out of range
 }}}

 Here's the generated SQL:

 {{{
 >>> str(User.objects.annotate(Count('logentry')).query)
 'SELECT "auth_user"."id", "auth_user"."username",
 "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email",
 "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active",
 "auth_user"."is_superuser", "auth_user"."last_login",
 "auth_user"."date_joined", COUNT("django_admin_log"."id") AS
 "logentry__count" FROM "auth_user" LEFT OUTER JOIN "django_admin_log" ON
 ("auth_user"."id" = "django_admin_log"."user_id") GROUP BY
 "auth_user"."id", "auth_user"."username", "auth_user"."first_name",
 "auth_user"."last_name", "auth_user"."email", "auth_user"."password",
 "auth_user"."is_staff", "auth_user"."is_active",
 "auth_user"."is_superuser", "auth_user"."last_login",
 "auth_user"."date_joined"'
 >>>
 str(User.objects.annotate(Count('logentry')).defer('first_name').query)
 'SELECT COUNT("django_admin_log"."id") AS "logentry__count" FROM
 "auth_user" LEFT OUTER JOIN "django_admin_log" ON ("auth_user"."id" =
 "django_admin_log"."user_id") GROUP BY "auth_user"."id",
 "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name",
 "auth_user"."email", "auth_user"."password", "auth_user"."is_staff",
 "auth_user"."is_active", "auth_user"."is_superuser",
 "auth_user"."last_login", "auth_user"."date_joined"'
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/16409>
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 post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to