All of this looks pretty good.  The 2 things I have to say are, a) I
think the F() way of dealing with that, in place of list comprehension
is the right way to go, there has been a lot of good work on that
patch, and I think it works well, conceptually, with this. b) Is there
any plan to make selecting on the primary key the default, so one can
do Count('authors') in place of Count('authors__id')?

Alex

On May 24, 8:18 am, "Nicolas E. Lara G." <[EMAIL PROTECTED]>
wrote:
> Hi Russell,
> I have been adding your test cases to the test suit and ran into
> troubles with some of them so I would like to know a bit more on what
> you were expecting from the queries:
>
> > * Does Author X have any friends?
> > (aggregate on a related object)
>
> Author.objects.filter(pk=1).aggregate(Count('friends__id'))
>
>
>
> > * Give me a list of all Books with more than 2 authors
> > (Query over the count of objects in a m2m relationship)
>
> >>>Book.objects.all().annotate(num_authors=Count('authors__name')).filter(num_authors__gt=2)
> > * Give me a list of all Authors that have no friends
> > (Query that counts when rows that don't exist in the m2m table)
>
> >>> Author.objects.all().annotate(num_friends=Count('friends__id', 
> >>> distinct=True), allow_nulls=True).filter(num_friends=0)
> > * Give me a list of all publishers that have published more than 10 books
> > (Query over the reverse direction of a FK)
>
> >>> Publisher.objects.all().annotate(num_books=Count('book__id')).filter(num_books__gt=10)
> > * Give me a list of all publishers that have published more than 10
> > books this year
> > (Query over the reverse direction of a FK, with a filter on the related 
> > object)
>
> >>> Publisher.objects.all().annotate(num_books=Count('book__id')).filter(num_books__gt=10,
> >>>  book__price__lt=50)
>
> So far so good. Though filter() is not yet implemented on aggregates
> the previous examples would work as soon as fileter starts working on
> aggregates. The generated SQL and what is planned for flter seems to
> match very well the problems in question.
>
> Now the hard ones:
>
> > * Give me a list of all Books that were written by X and one other author.
> > (Query that checks a count of m2m objects, plus membership of the m2m set)
>
> We have two possibilities here that would make sense.
> The first intuitive way to express this would be:
>
> >>> Book.objects.all().filter(authors__name__contains='Norvig').annotate(num_authors=Count('authors__id')).filter(num_authors__gt=1)
>
> This has problems because, given the nature of the SQL that is being
> generated, when the filtering occurs (It is transformed into a WHERE
> clause) we are restricting the rows to only those that have the author
> X. This way, counting them wont refer to the actual number of authors
> for each book but the number of authors currently selected (just 1).
> To work around this, the way of doing the query is this:
>
> >>> Book.objects.all().annotate(num_authors=Count('authors__id')).filter(authors__name__contains='Norvig',
> >>>  num_authors__gt=1)
>
> which would do the filtering after the aggregate so the count is
> executed on all the books.
>
> Should we consider this something that should be solved with
> documentation or should I implement the logic to restructure the query
> if an aggregate is executed on a QuerySet that has been filtered?
>
> > * Give me a list of all Authors that have published a book with at
> > least one other person
> > (Filters over a count generated on a related object)
>
> In this one I cheated doing this:>>> [a for a in 
> Author.objects.all().annotate(num_coleagues=Count('book__authors__id'), 
> num_books=Count('book__id', distinct=True)) if a.num_coleagues - a.num_books 
> > 0]
>
> but I am sure the intention was to get it done by just using the
> aggregation syntax. Do you have any suggestion on how to express this
> (with either existing or non-existant syntax)?
>
> An option for this would probably be the previously suggested F-
> syntax. So we could do:
>
> >>> Author.objects.all().annotate(num_coleagues=Count('book__authors__id'), 
> >>> num_books=Count('book__id', 
> >>> distinct=True)).filter(num_coleagues__gt=F(num_books))
> > * Give me the average price of all Books that were written by X and
> > one other author.
> > (Aggregate over objects discovered using membership of the m2m set)
>
> Also for this problem, how would you express it in aggregation syntax?
>
> An option that looks very good from the syntax point of view would be:
>
> >>> Book.objects.all().annotate(num_authors=Count('authors__id')).filter(num_authors__gt=1).aggregate(Avg('price'))
>
> but for this to work we would need to introduce the notion of
> subqueries which, AFAIK, have only been dealt with in extra().
>
> I believe it would be quite clean to introduce subqueries in common
> cases like this. Especially when dealing with aggregate since
> aggregate is a terminal clause.
>
> Cheers,
>
> Nicolas Lara
--~--~---------~--~----~------------~-------~--~----~
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 [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to