#28289: Queryset.count does not with work raw sql annotations on inherited model
fields
-------------------------------------+-------------------------------------
               Reporter:  Karolis    |          Owner:  nobody
  Ryselis                            |
                   Type:             |         Status:  new
  Uncategorized                      |
              Component:  Database   |        Version:  1.11
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Consider these models


 {{{
 class BaseItem(models.Model):
     title = models.CharField(max_length=32)


 class Item(BaseItem):
     pass
 }}}

 If I use a `RawSQL` annotation of `Item`'s queryset that includes one of
 the fields defined in `BaseItem` and call `.count()` on annotated
 queryset, it fails with the error:

 `django.db.utils.OperationalError: (1054, "Unknown column 'title' in
 'field list'")` (MySQL 5.7)

 code to reproduce the bug with given models:
 {{{
 queryset = Item.objects.all()
 queryset = queryset.annotate(title2=RawSQL("title", ()))
 queryset.count() # crashes
 }}}

 I have tracked down what causes this bug. `Query.get_aggregation` method
 drops `INNER JOIN` required to select the `title` field. Specifically,
 this code drops it:
 {{{
             if not inner_query.distinct:
                 # If the inner query uses default select and it has some
                 # aggregate annotations, then we must make sure the inner
                 # query is grouped by the main model's primary key.
 However,
                 # clearing the select clause can alter results if distinct
 is
                 # used.
                 if inner_query.default_cols and has_existing_annotations:
                     inner_query.group_by =
 [self.model._meta.pk.get_col(inner_query.get_initial_alias())]
                 inner_query.default_cols = False
 }}}
 Code is taken from Django 1.8 but 1.11 looks the same.
 `default_cols` is set to `False` and the `INNER JOIN` is dropped. Quick
 fix is to add a condition for setting `default_cols` to `False`:
 {{{
             if not inner_query.distinct:
                 # If the inner query uses default select and it has some
                 # aggregate annotations, then we must make sure the inner
                 # query is grouped by the main model's primary key.
 However,
                 # clearing the select clause can alter results if distinct
 is
                 # used.
                 if inner_query.default_cols and has_existing_annotations:
                     inner_query.group_by =
 [self.model._meta.pk.get_col(inner_query.get_initial_alias())]
                 if not has_existing_annotations:
                     inner_query.default_cols = False
 }}}

 I don't know if it could be done in a nicer way. I was able to reproduce
 this in 1.8.18 and 1.11.0

--
Ticket URL: <https://code.djangoproject.com/ticket/28289>
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/050.db04601467c9f43df67d99a0d205ce01%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to