Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: ManyToMany filter matching on ALL items in a list

Tags:

I have such a Book model:

class Book(models.Model):     authors = models.ManyToManyField(Author, ...)     ... 

In short:

I'd like to retrieve the books whose authors are strictly equal to a given set of authors. I'm not sure if there is a single query that does it, but any suggestions will be helpful.

In long:

Here is what I tried, (that failed to run getting an AttributeError)

# A sample set of authors target_authors = set((author_1, author_2))  # To reduce the search space,  # first retrieve those books with just 2 authors. candidate_books = Book.objects.annotate(c=Count('authors')).filter(c=len(target_authors))  final_books = QuerySet() for author in target_authors:     temp_books = candidate_books.filter(authors__in=[author])     final_books = final_books and temp_books 

... and here is what I got:

AttributeError: 'NoneType' object has no attribute '_meta' 

In general, how should I query a model with the constraint that its ManyToMany field contains a set of given objects as in my case?

ps: I found some relevant SO questions but couldn't get a clear answer. Any good pointer will be helpful as well. Thanks.

like image 559
iuysal Avatar asked Nov 07 '12 13:11

iuysal


People also ask

How can I filter a Django query with a list of values?

The sql query will be like SELECT * FROM mytable WHERE ids=[1, 3, 6, 7, 9] which is not true. You have to use in operator for this so you query will be like SELECT * FROM mytable WHERE ids in (1, 3, 6, 7, 9) for that Django provide __in operator.

What does objects all () return in Django?

all() Returns a copy of the current QuerySet (or QuerySet subclass). This can be useful in situations where you might want to pass in either a model manager or a QuerySet and do further filtering on the result.

How do you use get and filter together in Django?

This exception is also an attribute of the model class. Returns a new QuerySet containing objects that match the given lookup parameters. Basically use get() when you want to get a single unique object, and filter() when you want to get all objects that match your lookup parameters. Show activity on this post.

What is the purpose of filter () method in Django?

The filter() method is used to filter you search, and allows you to return only the rows that matches the search term.


1 Answers

Similar to @goliney's approach, I found a solution. However, I think the efficiency could be improved.

# A sample set of authors target_authors = set((author_1, author_2))  # To reduce the search space, first retrieve those books with just 2 authors. candidate_books = Book.objects.annotate(c=Count('authors')).filter(c=len(target_authors))  # In each iteration, we filter out those books which don't contain one of the  # required authors - the instance on the iteration. for author in target_authors:     candidate_books = candidate_books.filter(authors=author)  final_books = candidate_books 
like image 84
iuysal Avatar answered Oct 14 '22 06:10

iuysal