Python 使用Q对象筛选多个ForeignKey匹配

Python 使用Q对象筛选多个ForeignKey匹配,python,django,django-orm,django-1.3,django-q,Python,Django,Django Orm,Django 1.3,Django Q,我在Django 1.3下名为main的应用程序中使用以下数据初始化了这些模型: from django.db.models import Model, FloatField, CharField, ForeignKey, Q class Customer(Model): name = CharField(max_length=64) class Order(Model): customer = ForeignKey(Customer) order_total = F

我在Django 1.3下名为main的应用程序中使用以下数据初始化了这些模型:

from django.db.models import Model, FloatField, CharField, ForeignKey, Q

class Customer(Model):
    name = CharField(max_length=64)

class Order(Model):
    customer = ForeignKey(Customer)
    order_total = FloatField()
如何使用Q对象构造查询以查找拥有订单9和订单13的客户

如果不使用Q对象,我可以使用.filter方法两次来获得我想要的结果。如您所见,它使用两个联接来查找两个外键:

queryset = Customer.objects.filter(order__order_id=9).filter(order__order_id=13)

return HttpResponse("%s\n\n%s" % (queryset, queryset.query), content_type="text/plain")
[] 选择main_customer.id、main_customer.name 来自主要客户 在main\u customer.id=main\u order.customer\u id上内部联接main\u order 在main\u customer.id=T3.customer\u id上的内部连接main\u订单T3 其中main_order.order_id=9和T3.order_id=13 我试着用Q对象做同样的事情,如下所示。它没有理解我指的是两个不同的订单,一个id为9,一个id为13,而是认为我在寻找一个id为9和13的订单。这显然是不可能的,因此它不会返回任何结果:

q = Q(order__order_id=9) & Q(order__order_id=13)
queryset = Customer.objects.filter(q)

return HttpResponse("%s\n\n%s" % (queryset, queryset.query), content_type="text/plain")
[] 选择main_customer.id、main_customer.name 来自主要客户 在main\u customer.id=main\u order.customer\u id上内部联接main\u order 其中main_order.order_id=9,main_order.order_id=13 我希望Django的引擎能够等效地解释这两个查询,但显然Q对象的处理方式不同。如何使用Q对象通过多个外键引用过滤对象,而不是调用.filter多次?

我发现。我观察到的行为是预期的行为;如果在对.filter/.exclude的同一调用中应用多值关系的查询项,则与在不同调用中应用多值关系的查询项相比,它们的处理方式有所不同

如果我在同一个.filter调用中应用两个查询项

queryset=Customer.objects.filterQorder\uu订单id=9&Qorder\uu订单id=13 或等效为:。对象。筛选器顺序\u顺序\u id=9,顺序\u顺序\u id=13 …然后它只返回拥有满足两个约束条件的任何订单的客户,即订单id=9和订单id=13。这些术语在任何给定时间都必须指同一订单

另一方面,如果我使用两个不同的.filter调用应用查询条件

…它们不需要参考相同的顺序。这可以被看作是一个两步操作:所有客户的集合被过滤到那些拥有任何满足订单_id=9的订单的客户。然后,该结果集将进一步过滤到那些拥有任何订单且满足订单_id=13的客户。这两种情况下的顺序可能相同。没关系;这些台阶相互隔离


也许可以通过一个.filter调用从Q对象获得这种行为,但Django的ORM似乎不是这样使用的。

我想我找到了解决这种情况的方法:

使用filter~~QA | ~QB而不是filterQA&QB似乎可以产生预期的结果

这是基于这样一个事实,即A和B相当于notA或notB,并且只使用最终传递给单个筛选器的Q对象对多个ForeignKey进行筛选。它相当丑陋,但最终仍然只使用一个数据库查询

如上所述,最初的问题来自.filterA.filterB和filterA&B的不同行为参见中的示例,而filterQA&QB仅复制其中一种用途


在我的例子中,生成的SQL查询太复杂,无法确保该解决方案能够完美工作,但我想我会分享这个想法,因为我的测试证明它是可行的。请让我知道你是否确实证明了它/打破了它。

我不确定如何最好地描述我正在尝试做的事情。欢迎新标题建议。如果有人能找到一些方法,通过一个.filter/.exclude调用来实现这一点,我将非常感兴趣,如果它甚至可以远程使用,您就有权接受回答标记来实际回答问题。感谢您的建议。这些天我并没有太多地使用Django,所以我自己也无法测试它,但希望有一天谁会看到这篇文章,发现它很有用,并且可能会留下评论,让我们知道它是否对他们有用。
q = Q(order__order_id=9) & Q(order__order_id=13)
queryset = Customer.objects.filter(q)

return HttpResponse("%s\n\n%s" % (queryset, queryset.query), content_type="text/plain")
queryset = Customer.objects.filter(order__order_id=9).filter(order__order_id=13)