Q:

Django Queryset with filtering on reverse foreign key

I have the following Django model:
class Make:
   name = models.CharField(max_length=200)

class MakeContent:
   make = models.ForeignKey(Make)
   published = models.BooleanField()

I'd like to know if it's possible (without writing SQL directly) for me to generate a queryset that contains all Makes and each one's related MakeContents where published = True.

A:

Yes, I think you want
make = Make.objects.get(pk=1)
make.make_content_set.filter(published=True)

or maybe
make_ids = MakeContent.objects.filter(published=True).values_list('make_id', flat=True)
makes = Make.objects.filter(id__in=make_ids)

A:

I know this is very old question, but I am answering. As I think my answer can help others. I have changed the model a bit as follows. I have used Django 1.8.
class Make(models.Model):
    name = models.CharField(max_length=200)

class MakeContent(models.Model):
    make = models.ForeignKey(Make, related_name='makecontent')
    published = models.BooleanField()

I have used the following queryset.
Make.objects.filter(makecontent__published=True)

Hope it will help.

A:

Let me translate Spike's worded answer into codes for future viewers. Please note that each 'Make' can have zero to multiple 'MakeContent'
If the asker means to query 'Make' with AT LEAST ONE 'MakeContent' whose published=True, then Jason Christa's 2nd snippet answers the question.
The snippet is equivalent to
makes = Make.objects.select_related().filter(makecontent__published=True).distinct()

But if the asker means to query 'Make' with ALL 'MakeContent' whose published=True, then following the 'makes' above,
import operator
make_ids = [m.id for m in makes if 
    reduce(operator.and_, [c.published for c in m.makecontent_set.all()] ) 
]
makes_query = Make.objects.filter(id__in=make_ids)

contains the desired query.

