djangofiltercountmanytomanyfield

annotate model with aggregate state of manytomany field


I have a Stream that has permissions = ManyToManyField(Permission) Permission has a state field. If all of the streams's permission states are True then annotate stream with allowed=True, else annotate stream with allowed=False

from django.db import models

class Permission(models.Model):
    name = models.CharField(max_length=10),
    state = models.BooleanField()

class Stream(models.Model):
    permissions = models.ManyToManyField(Permission)

p1 = Permission.objects.create(state=True)
p2 = Permission.objects.create(state=False)
s = Stream.objects.create(name='s')
s.permissions.add([p1, p2])
s1 = Stream.objects.create(name='s1')
s1.permissions.add(p1)
s2 = Stream.objects.create(name='s2')
s2.permissions.add(p2)

# How can I do something like this?
annotated_streams = Stream.objects.annotate(allowed={... all([p.state for p in permissions]) ...})

[(s.name, s.allowed) for s in annotated_streams]

[('s', False), ('s1', True), ('s2', False)]


Solution

  • If I understand your question correctly, this should do it

    from django.db.models import Count, Case, When, BooleanField, Q
    
    annotated_streams = Stream.objects.alias(
        fcount = Count('permissions', filter=(Q(permissions__state=False)),
    ).annotate(
        allowed = Case(
            When(Q(fcount__gt=0), then=False)
            default = True, output_field=BooleanField()
        )
    )