#29229: QuerySet.values_list() combined with .extra() or .annotate() may produce
wrong .union()
-------------------------------------+-------------------------------------
     Reporter:  master               |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  1.11
  (models, ORM)                      |
     Severity:  Release blocker      |               Resolution:
     Keywords:  union values_list    |             Triage Stage:  Ready for
                                     |  checkin
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Old description:

> Regression introduced in 2.0, still present in 2.0.3.
>
> Easy context to reproduce the problem: suppose a Message model, in a
> postman app. Only one ordinary field is enough for the demo.
>
> {{{#!python
> qs1 = Message.objects.extra(select={'count': 0}).values_list('id',
> 'count').order_by()
> print(qs1.query)  # as expected:
> # SELECT (0) AS "count", "postman_message"."id"
> # FROM "postman_message"
>
> qs2 =
> Message.objects.values('somefield').annotate(count=models.Count('pk')).annotate(id=models.Max('pk')).values_list('id',
> 'count').order_by()
> print(qs2.query)  # as expected:
> # SELECT COUNT("postman_message"."id") AS "count",
> MAX("postman_message"."id") AS "id"
> # FROM "postman_message" GROUP BY "postman_message"."somefield"
>
> print(qs1.union(qs2).query)  # !! WRONG !! the qs2 part is truncated:
> # SELECT (0) AS "count", "postman_message"."id" FROM "postman_message"
> # UNION
> # SELECT MAX("postman_message"."id") AS "id" FROM "postman_message" GROUP
> BY "postman_message"."somefield"
> }}}
>
> Compared to version 1.11, it comes from this addition in
> db/models/sql/compiler.py/get_combinator_sql():
> {{{#!python
> if not compiler.query.values_select and self.query.values_select:
>     compiler.query.set_values(self.query.values_select)
> }}}
> Here, self.query.values_select is ('id',).
> For qs2, values_select is indeed empty, as coded in
> db/models/sql/query.py/set_values(),
> because in this case the two values_list() arguments are managed in
> annotation_names[].

New description:

 Regression introduced in 2.0, still present in 2.0.3 [Edit: and backported
 in 1.11.8].

 Easy context to reproduce the problem: suppose a Message model, in a
 postman app. Only one ordinary field is enough for the demo.

 {{{#!python
 qs1 = Message.objects.extra(select={'count': 0}).values_list('id',
 'count').order_by()
 print(qs1.query)  # as expected:
 # SELECT (0) AS "count", "postman_message"."id"
 # FROM "postman_message"

 qs2 =
 
Message.objects.values('somefield').annotate(count=models.Count('pk')).annotate(id=models.Max('pk')).values_list('id',
 'count').order_by()
 print(qs2.query)  # as expected:
 # SELECT COUNT("postman_message"."id") AS "count",
 MAX("postman_message"."id") AS "id"
 # FROM "postman_message" GROUP BY "postman_message"."somefield"

 print(qs1.union(qs2).query)  # !! WRONG !! the qs2 part is truncated:
 # SELECT (0) AS "count", "postman_message"."id" FROM "postman_message"
 # UNION
 # SELECT MAX("postman_message"."id") AS "id" FROM "postman_message" GROUP
 BY "postman_message"."somefield"
 }}}

 Compared to version 1.11 [Edit: I run 1.11.7 precisely], it comes from
 this addition in db/models/sql/compiler.py/get_combinator_sql():
 {{{#!python
 if not compiler.query.values_select and self.query.values_select:
     compiler.query.set_values(self.query.values_select)
 }}}
 Here, self.query.values_select is ('id',).
 For qs2, values_select is indeed empty, as coded in
 db/models/sql/query.py/set_values(),
 because in this case the two values_list() arguments are managed in
 annotation_names[].

--

Comment (by master):

 Precisions about versions.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29229#comment:3>
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 django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/064.b779afb5add0ac0de72b34af8c0afa99%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to