Let's say I have the following django model:
class Tag(models.Model):
key = models.CharField(max_length=64, unique=True)
class Site(models.Model):
key = models.CharField(max_length=64, unique=True)
tags = models.ManyToManyField(Tag, through='SiteTag')
class SiteTag(models.Model):
site = models.ForeignKey(Site, on_delete=models.RESTRICT)
tag = models.ForeignKey(Tag, on_delete=models.RESTRICT)
Where a site can have multiple tags using explicit Many-to-Many relationship. When I filter site with a specific tag in the following query other tags are filtered out where I mean give me sites with this tags and show all tags those sites have:
Site.objects.filter(tags__key__in=['type-1', 'type-2'])\
.annotate(tags=ArrayAgg("tags__key", distinct=True, filter=Q(tags__isnull=False)))
Then it indeed retrieve sites with either type-1
or type-2
but if a selected site has the type-3
tag I also want to collect it in the ArrayAgg
aggregation. Unfortunetly with this query I will only have ["type-1", "type-2"]
in annotated tags field instead of ["type-1", "type-2", "type-3"]
.
How can I filter sites using this criterion and still have all tags collected in the annotate section.
Sometimes writing the question is enough to find out the solution, the key was to call all
after annotate
and before filter
.
Site.objects.annotate(
tags=ArrayAgg("tags__key", distinct=True, filter=Q(tags__isnull=False)
).all().filter(tags__key__in=['type-1', 'type-2'])
This query filters as expected and returns all aggregated tags.