Django Queryset: filtering by related item manager
<p>I have model for pages that consist of a number of content blocks.</p>

<pre><code>class Page(models.Model):
    ...

class Block(models.Model):
    page = models.ForeignKey(Page)
    ...
</code></pre>

<p>The <code>Block</code> has a handful of other properties that determine whether it is considered to be "active" or not (a couple booleans and a datetime field). I have a manager for the <code>Block</code> model so that I can get a list of active Blocks</p>

<pre><code>Block.objects.active()
Page.objects.first().block_set.active()
</code></pre>

<p>I want to be able to write a queryset to return only <code>Page</code> objects that have active blocks. I would like to do this using the existing <code>Block</code> active manager, so that I am only defining what makes an "active" block once (DRY). IE something like:</p>

<pre><code>Page.objects.annotate(count=Count('block__active')).filter(count__gt=0)
</code></pre>

<p>Obviously that does not work since <code>active</code> is not a property of <code>Block</code>. Is there a way I can use the existing <code>Block</code> manager to achieve this?</p>

<p>As per what I know, there is no way to achieve it using single <code>queryset</code>, since you want to use the <code>active()</code> available within your manager. But you may achieve the result by adding the <a href="http://stackoverflow.com/questions/2642613/what-is-related-name-used-for-in-django">related name</a> to <code>Page</code> in <code>Block</code> model as:</p>

<pre><code>class Block(models.Model):
    page = models.ForeignKey(Page, related_name='related_block')
    ...
</code></pre>

<p>Now your code should be:</p>

<pre><code>active_blocks = Block.objects.active()  # Queryset with all active blocks
# Queryset of Pages with Block in 'active_blocks' 
active_pages = Page.objects.filter(related_block__in=active_blocks)
</code></pre>

<p>Now on this QuerySet, you may perform <code>annonate</code> or whatever you desire which is allowed on <code>Page</code>'s QuerySet.</p>

python django django-queryset