7

I have Query which shows different results when i use and or &

criteria1 = Q(id__gte=802, id__lte=1000)
criteria2 = Q(country_id__contains='UK')

I always have been using :

q = Mymodel.objects.filter(criteria1 & criteria2)

But in this particular case when i use & it always outputs a single row . (I also checked print q.query(), query comes out to be fine)

However, when i use and instead of &. Query gives correct output

q = Mymodel.objects.filter(criteria1 and criteria2)

what actually is happening under the hood ?

Shadow
  • 33,525
  • 10
  • 51
  • 64
Mahender Thakur
  • 510
  • 4
  • 13
  • `and` is not a operator that is specially implemented for `Q` objects. It will be evaluated by the normal Python rules as `criteria1 if not criteria1 else criteria2`. – Klaus D. Feb 13 '19 at 12:39

2 Answers2

2

The correct one is criteria1 & criteria2. criteria1 and criteria2 uses standard Python boolean logic and will be evaluated into criteria2, while criteria1 & criteria2 uses overloaded __and__ method and constructs correct compound Q object:

In [1]: from django.db.models import Q                                                                                                                                                                                                                                                                                                                        

In [2]: criteria1 = Q(id__gte=802, id__lte=1000)                                                                                                                                                                                                                                                                                                              

In [3]: criteria2 = Q(country_id__contains='UK')                                                                                                                                                                                                                                                                                                              

In [4]: criteria1 & criteria2                                                                                                                                                                                                                                                                                                                                 
Out[4]: <Q: (AND: ('id__gte', 802), ('id__lte', 1000), ('country_id__contains', 'UK'))>

In [5]: criteria1 and criteria2                                                                                                                                                                                                                                                                                                                               
Out[5]: <Q: (AND: ('country_id__contains', 'UK'))>
awesoon
  • 32,469
  • 11
  • 74
  • 99
  • thanks for clarifying this ....Using *and* is completly wrong . When i use *&* and run the same raw query in mysql it returns more than one row but orm returns single row ! ...Should this question be included in other thread ? – Mahender Thakur Feb 14 '19 at 08:24
  • Yes, please. Create a new question and include the actual code and SQL queries – awesoon Feb 14 '19 at 08:26
0

Q object define magic method __or__ and __and__. These functions allow & math and | operation to be overridden. Check this document

And if you want to know about difference between and and &, see this question

This is Q object code. You can find below code.

class Q(tree.Node):
    def __or__(self, other):
        return self._combine(other, self.OR)

    def __and__(self, other):
        return self._combine(other, self.AND)
Jrog
  • 1,469
  • 10
  • 29