Dmitry Risenberg
Dmitry Risenberg

Reputation: 2381

Django: Filter rows containing a set of values in ManyToManyField

I have the following model:

class Channel(models.Model):
    tags = models.ManyToManyField(Tag)

class Tag(models.Model):
    name = models.CharField( primary_key = True)

And want to get_or_create a channel that has exactly the given set of tags.

tags = map(lambda x: Tag.objects.get(name = x), ['tag1', 'tag2'])
channel = Channel.objects.get_or_create(tags = tags) # Here's the bug

Edit: looks like the problem is with the create part, because

Channel.objects.get(tags=tags)

works just fine. So it is the usual problem with saving a many-many relationship.

Upvotes: 1

Views: 548

Answers (2)

Nuno Maltez
Nuno Maltez

Reputation: 396

I don't think you can use get_or_create in this case. You need to do it in multiple steps:

  1. filter you channel list to get the channels with that exact list of tags, if there is one
  2. if the list is empty, create your channel and add the tags after the channel is created and has an ID

Ex:

tags = ['tag1', 'tag2']
channel = reduce(lambda channel_filter, x: channel_filter.filter(tags__name=x), tags, Channel.objects) # not checking if only one objetct is returned
if not channel:
    channel = Channel()
    channel.save()
    map(channel.tags.add, [Tag.objects.get(name = x) for x in tags])

Upvotes: 1

Josh Ourisman
Josh Ourisman

Reputation: 1118

What about something like:

tags = Tag.objects.filter(name__in=['tag1', 'tag2'])
channel = Channel.objects.get_or_create(tags=tags)

Upvotes: 0

Related Questions