Django - Q.add()使用运算符OR时的奇怪行为

时间:2014-07-31 19:00:40

标签: django django-queryset

所以,我正在尝试加入一堆Q()查询,特别是我希望运算符是用户定义的。

为了做到这一点,我正在尝试使用Q.add(Q,运算符)函数,并将运算符作为输入接收。

但是当我尝试将运算符设置为OR时,我遇到了一种奇怪的行为,如下所述:

q_1 = Q(field_one__id=5)
q_2 = Q(field_two__name='foo')
print q_1
> (AND: ('field_one__id', 5))
print q_2
> (AND: ('field_two__name','foo'))
q_1_and_q_2 = Q()
q_1_or_q_2 = Q()

q_1_and_q_2.connector = q_1_and_q_2.AND # This is the default operator but just in case.
q_1_or_q_2.connector = q_1_or_q_2.OR

# joining both versions using q.add() with the pre-set operator. clone() is used to avoid overriding q_1.
q_1_and_q_2 = q_1.clone().add(q_2, q_1_and_q_2.connector)  

q_1_or_q_2 = q_1.clone().add(q_2, q_1_or_q_2.connector)

#printing q_1_and_q_2 works as expected:
print q_1_and_q_2
> (AND: ('field_one__id', 5), ('field_two__name','foo'))

#But printing q_1_or_q_2 shows that q_1 was overridden by q_2
print q_1_or_q_2 
> (AND: ('field_two__name','foo'))

有人知道为什么会这样吗?

我认为一个像样的旁路看起来像这样:

from operator import or_, and_
if user_says_op == 'OR':
    op = or_
else:
    op = and_
q_1_with_q_2_operator_as_input = op(q_1,q_2)

但这样做感觉不对,如果可能的话我宁愿使用Q.add()

1 个答案:

答案 0 :(得分:0)

发生奇怪的行为是因为q_1的连接器与add()方法中指定的连接器不同。如果它们不相同,则返回输入的对象而不是新的连接Q对象。

示例:

>>> q_1 = Q(field_one__id=5)
>>> q_2 = Q(field_two__name='foo')
>>> q_1.connector = Q.AND
>>> print q_1.clone().add(q_2, Q.AND)
(AND: ('field_one__id', 5), ('field_two__name', 'foo')) # concatenated object
>>> q_1.connector = Q.OR
>>> print q_1.clone().add(q_2, Q.AND) 
(AND: ('field_two__name', 'foo')) # inputted data

<强>解决方案

在使用q_1

之前,只需正确定义add()的连接器即可
q_1 = Q(field_one__id=5)
q_2 = Q(field_two__name='foo')

q_1.connector = Q.AND
q_1_and_q_2 = q_1.clone().add(q_2, q_1.connector)  

q_1.connector = Q.OR
q_1_or_q_2 = q_1.clone().add(q_2, q_1.connector)

print q_1_and_q_2
print q_1_or_q_2 

输出:

(AND: ('field_one__id', 5), ('field_two__name', 'foo'))
(OR: ('field_one__id', 5), ('field_two__name', 'foo'))