views:

322

answers:

3

I have a problem making "exclude" querys on tables which have a many-to-many relationship through a third table. I have a table with projects, a table with people and a relationsship table with the flags "is_green, is_yellow, is_red", like:

class Project(models.Model):
    ...

class Person(models.Model):
    projects = models.ManyToManyField(Project, through='Status')

class Status(models.Model):
    person = models.ForeignKey(Person)
    project = models.ForeignKey(Project)
    is_green = models.BooleanField()
    ...

Now I want to make a query returning all persons, excluding those which do have the flag "is_red" in a specific project. But the following

Person.objects.exclude(project=p, status__is_red=True)

excludes everyone who is registered at project p but has status=red for any project he is registered. Is there a way to tie the second condition to the first?

My approach was to filter on the Status table directly, which works of course. But then I do have a list of "Status" objects instead of "Person" objects.

A: 

If you have a list of Status objects called 'objects', you can use

[s.person for s in objects]

to make it into a list of the corresponding Persons.

Ofri Raviv
Thanks for your answer. But that is exactly what I want to avoid. The question is, if there is a possibility get the list of Persons in one statement.
Daniel
+1  A: 

Maybe this? (untested)

Person.objects.exclude(id__in=Person.objects.filter(project=p, status__is_red=True).values(id))
celopes
Great! This idea works as desired. Although the syntax has to be slightly modified, because values() gives a list of dicts (at least in v1.0). This gives the exact result:Person.objects.exclude(id__in=Person.objects.filter(project=p, status__is_red=True).values_list('id', flat=True))
Daniel
Ah, yes... You are right on using values_list. I'm sorry. :-)
celopes
A: 

But I still wonder about one thing. According to the Django documentation the "exclude" function should be the opposite of the "filter" function. Nevertheless the filter call

Person.objects.filter(project=p, status__is_red=True)

works exactly as desired. It only returns the person that has status red=True on project p. So "filter" does not give the same datasets that "exclude" excludes. Is this a bug in Django? Does anyone use v1.1 and still discover the same behaviour?

Daniel