3

I have model for pages that consist of a number of content blocks.

class Page(models.Model):
    ...

class Block(models.Model):
    page = models.ForeignKey(Page)
    ...

The Block 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 Block model so that I can get a list of active Blocks

Block.objects.active()
Page.objects.first().block_set.active()

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

Page.objects.annotate(count=Count('block__active')).filter(count__gt=0)

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

smallbint
  • 41
  • 1
  • 3
  • Is all the data necessary to compute `active()` stored in the database? Because when it is you can use that logic to build an annotation. – Maccesch Sep 13 '16 at 23:48

2 Answers2

4

As per what I know, there is no way to achieve it using single queryset, since you want to use the active() available within your manager. But you may achieve the result by adding the related name to Page in Block model as:

class Block(models.Model):
    page = models.ForeignKey(Page, related_name='related_block')
    ...

Now your code should be:

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)

Now on this QuerySet, you may perform annonate or whatever you desire which is allowed on Page's QuerySet.

Community
  • 1
  • 1
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
0

Why not just add a boolean field on the model, something like is_active, and update it on save() or set_active()? Then you'll be able to query your Model by that field.

Andrey Shipilov
  • 1,986
  • 12
  • 14
  • One of the fields is a datetime field. Whether the model is active or not depends partly on the value of that field and the current time, so I have to evaluate it every time I load an object. – smallbint Sep 14 '16 at 17:20
  • Hm. From what you've described, it looks like that you define if the block is active using `is_active()` method on a class. Doesn't it mean that unless it's called, your Block's active/inactive state stays the same unless changed? – Andrey Shipilov Sep 15 '16 at 06:04