Django过滤多列值的"元组"的查询集

8on*_*ne6 17 python sql django django-queryset

说我有一个模型:

Class Person(models.Model):
    firstname = models.CharField()
    lastname = models.CharField()
    birthday = models.DateField()
    # etc...
Run Code Online (Sandbox Code Playgroud)

并说我有一个2个名字的列表:first_list = ['Bob', 'Rob']我有一个2个姓氏的列表:last_list = ['Williams', 'Williamson'].然后,如果我想选择名字所在的每个人,first_list我可以运行:

Person.objects.filter(firstname__in=first_list)
Run Code Online (Sandbox Code Playgroud)

如果我想选择其姓氏的所有人last_list,我可以这样做:

Person.objects.filter(lastname__in=last_list)
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.如果我想同时运行这两个限制,这很容易......

Person.objects.filter(firstname__in=first_list, lastname__in=last_list)
Run Code Online (Sandbox Code Playgroud)

如果我想进行or样式搜索而不是and样式搜索,我可以用Q对象来做:

Person.objects.filter(Q(firstname__in=first_list) | Q(lastname__in=last_name))
Run Code Online (Sandbox Code Playgroud)

但我想到的是一些更微妙的东西.如果我只想返回一个返回名字和姓氏的特定组合的查询集,该怎么办?即我要返回Person的哪些对象(Person.firstname, Person.lastname)zip(first_names, last_names).即我想找回任何一个名叫鲍勃威廉姆斯或罗伯威廉姆森的人(但不是任何一个名叫鲍勃威廉姆森或罗布威廉姆斯).

在我的实际使用情况,first_listlast_list就都有〜100元.

目前,我需要在Django应用程序中解决此问题.但我也很好奇在更一般的SQL上下文中处理这个问题的最佳方法.

谢谢!(如果我能说清楚的话,请告诉我.)

bru*_*ers 21

除了一个大的OR子句,我没有看到太多的解决方案:

import operator
from itertools import izip
query = reduce(
    operator.or_, 
    (Q(firstname=fn, lastname=ln) for fn, ln in izip(first_list, last_list))
    )

Person.objects.filter(query)
Run Code Online (Sandbox Code Playgroud)


Ami*_*ber 6

bruno的答案有效,但对我来说却很肮脏-在Python级别和SQL级别(OR的大连接)都如此。至少在MySQL中,您可以使用以下SQL语法:

SELECT id FROM table WHERE (first_name, last_name) IN
       (('John','Doe'),('Jane','Smith'),('Bill','Clinton'))
Run Code Online (Sandbox Code Playgroud)

Django的ORM没有提供直接的方法来执行此操作,因此我使用原始SQL:

User.objects.raw('SELECT * FROM table WHERE (first_name, last_name) IN %s',
      [ (('John','Doe'),('Jane','Smith'),('Bill','Clinton')) ])
Run Code Online (Sandbox Code Playgroud)

(这是一个具有一个元素的列表,与查询中的单个%s匹配。该元素是可重复的元组,因此%s将转换为SQL元组列表)。

笔记:

  1. 如我所说,这适用于MySQL。我不确定还有哪些后端支持此语法。
  2. 与此行为相关的python-mysql中的错误已在2013年11月/ MySQLdb 1.2.4中修复,因此请确保您的Python MySQLdb库不早于此。