Hi,
I ran in this today. Say i have these two models in my app called atest

class Person(models.Model):
    name = models.CharField(max_length=255)
    age = models.IntegerField(null=True)

class Car(models.Model):
    owner = models.ForeignKey('Person', related_name='cars')
    brand = models.CharField(max_length=255)

Suppose that some persons have more than one car, some have one and others 
none.
First case, i want to get a list of persons with the number of cars they 
have *that includes 0*

*Person.objects.all().annotate(Count('cars')).order_by('-cars__count')*

it creates a query like:

*SELECT atest_person.id, atest_person.name, atest_person.age, 
COUNT(atest_car.id) AS cars__count*
*FROM atest_person*
*LEFT OUTER JOIN atest_car ON (atest_person.id = atest_car.owner_id)*
*GROUP BY atest_person.id,*
*         atest_person.name,*
*         atest_person.age*
*ORDER BY cars__count DESC*

This is all fine, 

But what if i want to get a list of persons with the number of "Ford" cars 
they have?
You might say:
*
Person.objects.filter(cars__brand='Ford').annotate(Count('cars')).order_by('-cars__count')
*

generates a query like:

*SELECT atest_person.id, atest_person.name, atest_person.age, 
COUNT(atest_car.id) AS cars__count*
*FROM atest_person*
*LEFT OUTER JOIN atest_car ON (atest_person.id = atest_car.owner_id)*
*WHERE atest_car.brand = 'Ford'*
*GROUP BY atest_person.id,*
*         atest_person.name,*
*         atest_person.age*
*ORDER BY cars__count DESC*

I get a list of persons with how many Ford cars they have *IF* they have 
one or more, those that don't have a Ford car won't make it into the
resultset, with a 0 for cars__count like in the previous query where we 
didn't care for the model. This is because of the WHERE that filters out
nulls.

But i want the result like the previous one, with a 0 if they don't have 
one.

In SQL this is, put the car brand condition in the JOIN clause:

*SELECT atest_person.name, count(atest_car.id) as "cars__count"*
*FROM atest_person*
*LEFT OUTER JOIN atest_car ON (atest_person.id = atest_car.owner_id)*
*AND atest_car.brand = 'Ford'*
*GROUP BY atest_person.name*
*ORDER BY **cars__count** desc*

So i have two options,
one to execute a raw query or something like

*Person.objects.all().extra(*
*    select = {*
*        'cars__count':'SELECT count(id) FROM atest_car WHERE 
atest_person.id = atest_car.owner_id AND atest_car.brand = %s'*
*    },*
*    select_params = ['Ford']*
*).order_by('-cars__count')*

that makes this query:

*SELECT*
*  (SELECT count(id)*
*   FROM atest_car*
*   WHERE atest_person.id = atest_car.owner_id*
*     AND atest_car.brand = 'Ford') AS cars__count,*
*       atest_person.id,*
*       atest_person.name,*
*       atest_person.age*
*FROM atest_person*
*ORDER BY cars__count DESC *

But i would really like if one could only pass a parameter to annotate or 
count to include zeroes.
Sorry for the long read, a fine example of this problem is here
http://searchoracle.techtarget.com/answer/LEFT-OUTER-JOIN-with-ON-condition-or-WHERE-condition

*
*

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" 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].
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to