Patterson
Patterson

Reputation: 336

Django-taggit - How to filter all tagged objects, repeating them for each tag?

I need to select all the tagged objects so that they are repeated for each tag marked on them.

For example:

class Wallet(BaseModel):
    code = models.CharField(max_length=85, verbose_name="Wallet")
    tags = TaggableManager(blank=True)

    def __str__(self):
        return f"{self.code}"

Then if I run the following code:

wallet_1 = Wallet.objects.create(code=1)
wallet_1.tags.add(*["A", "B"])
wallet_2 = Wallet.objects.create(code=2)
wallet_2.tags.add(*["C"])

I need to select all the wallets so that if the wallet_1 has two tags the select should return wallet_1 twice so the result would be a queryset containing:

<QuerySet [<Wallet: 1>, <Wallet: 1>, <Wallet: 2>]>

Is it possible to do that?

Upvotes: 1

Views: 395

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476493

Yes, you can annotate the wallets with the tag name, so:

from django.db.models import F

Wallet.objects.annotate(
    tag_name=F('tags__name')
)

You can filter Wallets that have not tags with:

from django.db.models import F

Wallet.objects.filter(
    tags__isnull=False
).annotate(
    tag_name=F('tags__name')
)

The Wallet objects that arise from this QuerySet will have an extra attribute .tag_name that specifies the tag name. So the wallet_1 will occur twice each wallet will have a different value for .tag_name.

Note that you do not need to use iterable unpacking here, you can simply write:

wallet_1 = Wallet.objects.create(code=1)
wallet_1.tags.add('A', 'B')
wallet_2 = Wallet.objects.create(code=2)
wallet_2.tags.add('C')

this is basically what the iterable unpacking will do.

Upvotes: 1

Related Questions