2

I'm trying to find Problem objects having all the tags contained in tags related to it.

I have the following models.

class Tag(models.Model):
    name = models.CharField(verbose_name='Tag Name', max_length=50)
    description = models.CharField(verbose_name='Description', max_length=100, null=True, blank=True)

class Problem(models.Model):
    name = models.CharField(verbose_name='Problem Name', max_length=250)
    contest_info = models.ManyToManyField(ContestInfo, verbose_name='Contest Info')
    tags = models.ManyToManyField(Tag, verbose_name='Tags')

I've followed these posts: Post-1 and Post-2.
But, none worked.

My approaches.

Approach 1

query = [Q(tags__id__in=[tag]) for tag in tags]
problems = problems.filter(reduce(__and__, query))

Returns empty queryset.

Approach 2

for tag in tags:
    problems &= problems.filter(tags__id__in=[tag])

Returns result of OR instead of AND. Using intersection() also gives the same result.

I want to get those problems which have all the tags in the list. How to do this ?

N.B: problems is a queryset and tags is list of ids of Tag objects.

MD. Khairul Basar
  • 4,976
  • 14
  • 41
  • 59

2 Answers2

1

For postgresql what you can is this (tested):

from django.contrib.postgres.aggregates import JSONBAgg

problems = Problem.objects.annotate(tags_ids=JSONBAgg('tags__id'))
problems = problems.filter(tags_ids__contains=tags, tags_ids__contained_by=tags)

*where "tags is list of ids of Tag objects."

Basalex
  • 1,147
  • 9
  • 20
0

I solved this problem following this answer. Thanks to @itzMEonTV.
But, it requires looping and I would like to achieve this without looping if possible.

Here's the solution.

for tag in tags:
    problems = problems.filter(tags__id=tag)
MD. Khairul Basar
  • 4,976
  • 14
  • 41
  • 59