Hi all,

I've been working my way through a couple of aggregation tickets, and
I've hit a bit of an inconsistency that I think may need to be
addressed. The problem lies in the interaction of values() and
annotate(), especially as compared to the interaction of extra() and
values().

Ordinarily, values() directs the ORM to return the raw values, rather
than an object instance. values('x','y','z') directs the ORM to return
only the named columns x,y, and z.

If the query has an extra clause(), values('x','y','z') will only
return the nominated columns. If an extra select column isn't
mentioned specifically in the values clause, it isn't included in the
result set.

However, if the query contains an annotate() clause, the annotated
value is always returned in the values() set, regardless of whether it
is mentioned in the values clause or not.

Aside from this being inconsistent, it's a little inconvenient when it
interacts with the behaviour introduced in [9701] - the ability to use
querysets as rvalues for __in queries. If you have a query with an
annotate in it, you essentially can't use it as an rvalue, because it
will always have a minimum of 2 columns, which means you can't use a
query with an annotation in an __in clause (which require a single
column).

So - the initial suggestion here is to modify ValuesQuerySet so that
annotations aren't automatically included in the result set - you
would need to specifically mention the annotate column in order for it
to be returned.

There is a slight complication, though. The ordering of values() and
annotate() is significant - values() controls the grouping of
annotated values if it precedes the annotate(). However, you can't
mention the annotated column in a values() clause before it is
specified, so are left in a situation where you can't actually return
the annotated value. For example in the query:

>>> Book.values('title','isbn').annotate(n_authors=Count('authors'))

n_authors wouldn't be returned in the result set, and there isn't any
way to add it to the returned values.

So - some options:

1) Leave things as-is. Annotated columns always appear in the result
set. This is inconsistent with extra(), and means you can't use
annotated queries in __in clauses.

2) Modify things slightly - annotate() calls before a values() call
aren't automatically added to the results, but annotate() calls after
values() are included automatically. This would allow annotations to
always be returned, optionally under those circumstances that allow
(i.e., annotate() before values()).

3) Rely on multiple calls to values() to get annotate columns into the
result set. i.e., the previous example would need to become something
like:

>>> Book.values('title','isbn').annotate(n_authors=Count('authors')).values('title','isbn','n_authors')

This has the potential to be a bit fragile - we would need to put in
all sorts of checks for changes in column lists between successive
calls to values() - but it would allow all combinations of annotation.

Opinions? Any other options I may have missed?

Yours
Russ Magee %-)

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to