我一直在尝试根据某些函数参数动态构造过滤器列表。
我使用Q
对象构建了一个谓词列表,最后我使用了以下条件来构建一个谓词:
filters = []
... some code appending Q objects to filters ...
combined_filter = reduce(and_, filters)
然后我用以下查询我的数据库对象:
MyModel.objects.filter(combined_filter)
当我尝试将Q
对象与operator.and_
组合在一起时,我注意到了一些奇怪的行为。
例如比较以下输出:
items = Item.objects.filter(and_(is_metal, ~is_wood))
print([i.name for i in items])
items = Item.objects.filter(is_metal and ~is_wood)
print([i.name for i in items])
items = Item.objects.filter(is_metal, ~is_wood)
print([i.name for i in items])
我得到:
['Table', 'Container']
['Container']
['Table', 'Container']
and_
和and
之间行为不同的原因是什么?
我的预期输出是['Container']
(请参见下面的完整示例,“容器”是唯一只包含“金属”作为材料的东西,应该排除“表”,因为它也具有“木头” )。
后续问题将是:使用and
时如何获得reduce
的行为?
我的Django版本是2.0.7 我在https://repl.it/repls/AgonizingBossyEfficiency
上重现了这个确切的问题如果上面的链接消失了,我修改过的所有代码都在下面:
models.py :
from django.db import models
class Material(models.Model):
name = models.CharField(max_length=50)
class Item(models.Model):
name = models.CharField(max_length=50)
materials = models.ManyToManyField(Material)
views.py :
from django.shortcuts import render
from django.db import transaction
from django.db.models import Q
from operator import and_
from .models import Material, Item
# Create your views here.
def home(request):
with transaction.atomic():
metal = Material(name="metal")
metal.save()
wood = Material(name="wood")
wood.save()
table = Item(name="Table")
table.save()
table.materials.add(metal, wood)
table.save()
chair = Item(name="Chair")
chair.save()
chair.materials.add(wood)
chair.save()
container = Item(name="Container")
container.save()
container.materials.add(metal)
container.save()
is_metal = Q(materials__name__in = ('metal',))
is_wood = Q(materials__name__in = ('wood',))
items = Item.objects.filter(and_(is_metal, ~is_wood))
print([i.name for i in items])
items = Item.objects.filter(is_metal and ~is_wood)
print([i.name for i in items])
items = Item.objects.filter(is_metal, ~is_wood)
print([i.name for i in items])
raise Exception('nope')
return render(request, 'main/index.html')
答案 0 :(得分:0)
Ilja指出,我的问题实际上是重复的。
我的主要问题是认为operator.and_
适用于逻辑and
。
但是事实并非如此,operator.and_
是按位运算符。
如果我比较operator.and_(is_metal, is_wood)
和is_metal & is_wood
的行为(与is_metal && is_wood
== is_metal and is_wood
相反),我的确会得到相同的结果。
所以我的问题是我正在使用按位运算,并且我希望在逻辑和运算符上使用。