1

I have a interesting Django problem.

Consider the following:

Model.objects.filter(Q(id='test1') and Q(id='test2'))

this returns the expected results, however

Model.objects.filter(Q(id='test1') & Q(id='test2'))

DOES NOT!!

What's going on here?

Sam Hammamy
  • 10,819
  • 10
  • 56
  • 94

3 Answers3

4

If you want Django ORM to return test1 and test2, you should use :

Model.objects.filter(Q(id='test1') | Q(id='test2'))

Model.objects.filter(Q(id='test1') & Q(id='test2')) means return model objects whose id is test1 while its is test2 at the same time. Of course, django will return an empty QuerySet.

and is a boolean operator in Python. For operation x and y the result is if x is false, then x, else y. Thus Q(id='test1') and Q(id='test2') equals Q(id='test1'), it is not what you want.

&/| is the the bitwise and/or operator.

BTW, there's no way to override the boolean operator, but you can override &/| operators in your class by define a method named __and__ / __or__.

below is the source code of the django Q object[github]:

class Q(tree.Node):
    """
    Encapsulates filters as objects that can then be combined logically (using
    & and |).
    """
    # Connection types
    AND = 'AND'
    OR = 'OR'
    default = AND

    def __or__(self, other):
        return self._combine(other, self.OR)

    def __and__(self, other):
        return self._combine(other, self.AND)
    ...
Leonardo.Z
  • 9,425
  • 3
  • 35
  • 38
0

according to the following tutorial

& is a Binary AND Operator copies a bit to the result if it exists in both operands.

Example: Assume if a = 60; and b = 13; Now in binary format they will be as follows:

a = 0011 1100

b = 0000 1101

(a & b) will give 12 which is 0000 1100

and Called Logical AND operator. If both the operands are true then then condition becomes true.

Example: (a and b) is true.

So the & was performing binary addition on your query set. Interesting.

sirFunkenstine
  • 8,135
  • 6
  • 40
  • 57
  • 1
    Ok, so my main problem is that I have a list of search params, that I need to dynamically create a (Q(one) and Q(two)) from a list [one, two]. I can't use reduce(operator.and_, Q(i) for i in LIST)) because and_ is bitwise!!! So what can I do?? – Sam Hammamy Oct 25 '13 at 01:21
  • My django knowledge is still pretty limited but this [question](http://stackoverflow.com/questions/310732/in-django-how-does-one-filter-a-queryset-with-dynamic-field-lookups) looks similar to what your looking for. Sorry i cant be of more help. Good luck! – sirFunkenstine Oct 25 '13 at 01:35
0

I think you want OR here, and not AND

filters = ['test1', 'test2', 'test3', 'test4']
filtered = Model.objects.filter(Q(id = filters[0]))
for f in filters[1:]:
     subset = Model.objects.filter(Q(id = f))
     filtered = filtered | subset
kgu87
  • 2,050
  • 14
  • 12