#33282: django.db.utils.ProgrammingError: more than one row returned by a 
subquery
used as an expression
-------------------------------------+-------------------------------------
     Reporter:  Antonio Terceiro     |                    Owner:  nobody
         Type:  Bug                  |                   Status:  closed
    Component:  Database layer       |                  Version:  3.2
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:  needsinfo
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Antonio Terceiro):

 Hi, I spent some time debugging this today. This seems to be caused by
 `get_group_by_cols()` returning an incorrect value for a `Query` object.
 In a pdb session against the main branch of the git repository, I get
 this:

 {{{
 $ pdb3 ./manage.py runscript test
 > /home/terceiro/src/linaro/lava/manage.py(22)<module>()
 -> import argparse
 (Pdb) break /home/terceiro/src/django/django/db/models/lookups.py:434
 Breakpoint 1 at /home/terceiro/src/django/django/db/models/lookups.py:434
 (Pdb) c
 >
 /home/terceiro/src/django/django/db/models/lookups.py(434)get_group_by_cols()
 -> cols.extend(self.rhs.get_group_by_cols())
 (Pdb) p self.rhs
 <django.db.models.sql.query.Query object at 0x7f6ddb7bd580>
 (Pdb) p self.rhs.get_group_by_cols()
 [<django.db.models.sql.query.Query object at 0x7f6ddb7bd580>]

 }}}

 In commit 35431298226165986ad07e91f9d3aca721ff38ec, which caused this,
 {{{django.db.models.sql.query.Query}}} is made a subclass of
 {{{django.db.models.expressions.BaseExpression}}}.
 BaseExpression.get_group_by_calls is implemented like this:

 {{{
     def get_group_by_cols(self, alias=None):
         if not self.contains_aggregate:
             return [self]
         cols = []
         for source in self.get_source_expressions():
             cols.extend(source.get_group_by_cols())
         return cols
 }}}

 Since BaseExpression also hardcodes {{{contains_aggregate}}} to False,
 that first if statement always applies. Providing an appropriate
 implementation of contains_aggregate to Query fixes things for me here:

 {{{
 diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
 index 2c5f11cbbf..f7c43ff622 100644
 --- a/django/db/models/sql/query.py
 +++ b/django/db/models/sql/query.py
 @@ -414,6 +414,11 @@ class Query(BaseExpression):
          annotation.set_source_expressions(new_exprs)
          return annotation, col_cnt

 +    @cached_property
 +    def contains_aggregate(self):
 +        annotations = self.annotations.values()
 +        return any(getattr(ann, 'contains_aggregate', True) for ann in
 annotations)
 +
      def get_aggregation(self, using, added_aggregate_names):
          """
          Return the dictionary with the values of the existing
 aggregations.
 }}}

 I wasn't able to write an unit tests for this so far, though.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33282#comment:4>
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 view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/066.654d0f66c5e1dfd4383575f65de66776%40djangoproject.com.

Reply via email to