#28107: Can't perform annotation on related table when un-managed model is 
backed
by a DB view
-------------------------------------+-------------------------------------
     Reporter:  powderflask          |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  master
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:  QuerySet.extra       |             Triage Stage:  Accepted
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Description changed by powderflask:

Old description:

> I'm working with a legacy DB (ArcSDE database -- really ugly) -- have
> been able to accommodate its oddities without resorting much to raw SQL,
> but  django upgrade (1.8 --> 1.11) caused a previously working annotation
> to fail:
> {{{ psycopg2.ProgrammingError: :column ... must appear in the GROUP BY
> clause or be used in an aggregate function }}}
>
> **DB:  PostgreSQL 9.3.16 **   (i.e., this is not same issue as #26758 )
> Python3.6, Django1.11
>
> The annotation simply counts the number of related records from a related
> 'attachments' table:
> {{{ qs.annotate(num_attachments=Count('attachments')) }}}
>
> The root cause appears to be that the relation between the model and
> attachments tables uses a unique field ''other than the main model's
> primary key'' (I know -- told you it was ugly - ArcSDE does not really
> support relations, except they implement attachments with this odd ball
> ** sigh **).
> The change in behaviour seems to manifest from #19259 (I believe
> django1.8 added all fields to the groupby clause).
> Since django now includes only the primary key in the groupby clause,
> postgresql won't do this aggregation across a relation that uses a non-pk
> field.
>
> I suspect there is a general issue here that aggregations on a related-
> table won't work in postgresql unless the relation is on the primary key
> field (so, yeah, basically this issue applies to almost no one,
> right...).
>
> Seems likely there is a better solution to this, but after a half-day of
> search / effort, I resorted to the following:
> {{{
> qs.extra(select={'num_attachments':
>             'SELECT COUNT("attachmentid") FROM {attach_table} WHERE
> {attach_table}.rel_globalid = {model_table}.globalid'.format(
>                     model_table  = qs.model._meta.db_table,
>                     attach_table =
> qs.model.AttachmentModel._meta.db_table,
>             )},)
> }}}
>
> This works and achieves my goal -- to annotate model with the number of
> related attachments.
> Since the {{{ model.attachments.count() }}} query works just fine, I'm
> considering eliminating this annotation and replacing with a property on
> the model class, what's one more query...  I'm sure there must be an
> smoother way, but it eludes me...
>
> Since the docs suggested to open a ticket for queries that could not be
> resolved without resorting to extra(), here it is, for whatever its
> worth.  Hope this hasn't been a complete waste of time for you.

New description:

 I'm working with a legacy DB (ArcSDE database -- really ugly) -- have been
 able to accommodate its oddities without resorting much to raw SQL, but
 django upgrade (1.8 --> 1.11) caused a previously working annotation to
 fail:
 {{{ psycopg2.ProgrammingError: :column ... must appear in the GROUP BY
 clause or be used in an aggregate function }}}

 **DB:  PostgreSQL 9.3.16 **   (i.e., this is not same issue as #26758 )
 Python3.6, Django1.11

 The annotation simply counts the number of related records from a related
 'attachments' table:
 {{{ qs.annotate(num_attachments=Count('attachments')) }}}

 The root cause appears to be that the relation between an unmanaged model
 (backed by a DB View) and attachments tables uses a unique field ''other
 than the main model's primary key'' (I know -- told you it was ugly -
 ArcSDE does not really support relations, except they implement
 attachments with this odd ball ** sigh **).
 The change in behaviour seems to manifest from #19259 (I believe django1.8
 added all fields to the groupby clause).
 Since django now includes only the primary key in the groupby clause,
 postgresql won't do this aggregation across a relation that uses a non-pk
 field.

 I suspect there is a general issue here that aggregations on a related-
 table won't work in postgresql unless the relation is on the primary key
 field (so, yeah, basically this issue applies to almost no one, right...).
 UPDATE:  The root cause is actually that Postgresql treats Views
 differently than Tables w.r.t. what is required in the group by clause.

 Seems likely there is a better solution to this, but after a half-day of
 search / effort, I resorted to the following:
 {{{
 qs.extra(select={'num_attachments':
             'SELECT COUNT("attachmentid") FROM {attach_table} WHERE
 {attach_table}.rel_globalid = {model_table}.globalid'.format(
                     model_table  = qs.model._meta.db_table,
                     attach_table =
 qs.model.AttachmentModel._meta.db_table,
             )},)
 }}}

 This works and achieves my goal -- to annotate model with the number of
 related attachments.
 Since the {{{ model.attachments.count() }}} query works just fine, I'm
 considering eliminating this annotation and replacing with a property on
 the model class, what's one more query...  I'm sure there must be an
 smoother way, but it eludes me...

 Since the docs suggested to open a ticket for queries that could not be
 resolved without resorting to extra(), here it is, for whatever its worth.
 Hope this hasn't been a complete waste of time for you.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/28107#comment:11>
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/069.3288c5c19768c0aab950351ee3ab7409%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to