4

I realized my question is simpler, I'm leaving the body of the previous question as further explanation. I'm having issues doing AND queries with Q objects. How does it work? I've provided 4 examples and the only time I can get it to work is when chaining filters, however I want to avoid that to build more complex queries using OR as well.


I'm having issues doing a query across relationships with Q objects when AND'ing the same queried argument.

Modifying a little bit the example on the Django documentation page: A 'Blog' model has a m2m relationship with an 'Author' model. Let's say I want to query for all the blogs that meet the following criteria: Bob and Mary are the authors or Steve is the author. I'm pretty sure the only way to do this is with Q objects, so I'm breaking it down in chunks. This is what I've attempted so far:

Blog.objects.filter(Q(author__name='bob', author__name='mary'))

returns with SyntaxError: keyword argument repeated

Blog.objects.filter(Q(author__name='bob') & Q(author__name='mary'))

returns an empty queryset

Blog.objects.filter(author__name='bob', author__name='mary')

returns with SyntaxError: keyword argument repeated

Blog.objects.filter(author__name='bob').filter(author__name='mary')

returns the correct result, however, now I lost the ability to use Q objects for the OR arguments (I believe), so I would have to do another query and have the result in 2 querysets, which is not desired

I'm not sure I explained my situation properly, or if I'm even going about it the correct way. Anybody has any advice?

Tomasz Jakub Rup
  • 10,502
  • 7
  • 48
  • 49
  • Looks like a duplicate of http://stackoverflow.com/questions/5301996/how-to-do-many-to-many-django-query-to-find-book-with-2-given-authors – solarissmoke Oct 21 '15 at 03:16
  • try this Blog.objects.filter((Q(author__name='bob') & Q(author__name='mary')) | Q(author__name='steve')) – Manjunath Satyamurthy Oct 21 '15 at 03:23
  • @solarissmoke unfortunately, that answer is basically my 4th example. I'm chaining filters and I can't do an OR unless I run another query. – elspanishgeek Oct 21 '15 at 03:31
  • @ManjunathSatyamurthy It always returns the OR argument because the left part is my 2nd example which always return empty. – elspanishgeek Oct 21 '15 at 03:32
  • @spanishgeek not sure what you mean when you say you would have to do another query/have the result in two querysets? Your fourth (chained) query will return *one* query set which matches all books that have both Bob and Mary as authors. – solarissmoke Oct 21 '15 at 04:01
  • Oh, never mind - I understand now. You want to do an additional OR query in addition to that set of authors. – solarissmoke Oct 21 '15 at 04:05

2 Answers2

0

I believe this should work:

Blog.objects.annotate(author2=author).filter(Q(author__name='bob') & Q(author2__name='mary'))
FrederikVds
  • 551
  • 4
  • 11
  • This works for this specific example, I wasn't sure if to post a generalized version of my question or the complete thing. I'm trying to create the query dynamically, that's why I wanted to use Q objects so I could just append & or | depending on what I needed. – elspanishgeek Oct 22 '15 at 00:04
  • This is as general as it will get (with Q objects). When you use the same field twice in a Q lookup, it assumes you mean the same element. Otherwise, it would be impossible to do the following: `Blog.objects.filter(Q(author__firstname='bob') & Q(author__lastname='smith'))` If it worked like you wanted, it would match any blog for which some author has first name bob and another author has last name smith, which would probably not be what you want. – FrederikVds Oct 22 '15 at 05:42
  • That's what I figured, that it was more a problem of my understanding and less about the actual limitations of Q objects. Fortunately, I was able to find something that suited my needs! – elspanishgeek Oct 23 '15 at 20:14
0

So, it seems that you just can't use Q objects to AND the same argument, even if it's in a M2M relationship. I found a solution on Reddit to basically construct multiple queries with chained filters and then OR them together, eliminating the need for Q objects:

b1 = Blog.objects.filter(authors__name='bob').filter(authors__name='mary')
b2 = Blog.objects.filter(authors__name='steve')
qs = b1 | b2