Harry
Harry

Reputation: 13329

Django Filter deduce ManyToMany

Simple models with many to many relations on the Tag field.

class Tag(models.Model):
    description = models.TextField()

class Species(models.Model):
    name = models.CharField(max_length=256)
    tags = models.ManyToManyField(Tag)

Now Im trying this, and as I understand, it should return a list that matches every tag_description in the tags list:

tag_list = request.GET.get('q').split(',')
species = Species.objects.filter(reduce(and_, [Q(tags__description=c) for c in tag_list]))

But its returning an empty list. It should be returning some objects.

It works when I give it only one tag

any idea why this is happening?

Im using it as was shown in this answer: https://stackoverflow.com/a/8636836/228660

Upvotes: 1

Views: 561

Answers (2)

schillingt
schillingt

Reputation: 13731

I think another way of doing this would be:

tag_list = request.GET.get('q').split(',')
species = Species.objects.all().distinct()
for tag in tag_list:
    species = species.filter(tags__description=tag)
else:
    species = Species.objects.none()

Upvotes: 1

Wolph
Wolph

Reputation: 80031

As you can actually see in the comments of that question, it doesn't actually work ;) The problem is that you will be using the same join (which means the same object) for all filters. Unless all items in tag_list are identical this will never work. The problem lies within the Q objects instead of full filtered queries.

tag_list = request.GET.get('q').split(',')

# Generate a query with all species
all_species = Species.objects.all()
# Generate a list with the separately filtered species
filtered_species = [all_species.filter(tags__description=c) for c in tag_list]
# Join the filtered species together using the same method :)
species = reduce(and_, filtered_species, all_species)

Upvotes: 1

Related Questions