如何在Django中dynamic组合一个OR查询filter?

从一个例子中你可以看到一个多重查询filter:

Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3)) 

例如,这导致:

 [<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] 

但是,我想从列表中创build此查询filter。 怎么做?

例如[1, 2, 3] -> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))

你可以链接你的查询如下:

 values = [1,2,3] # Turn list of values into list of Q objects queries = [Q(pk=value) for value in values] # Take one Q object from the list query = queries.pop() # Or the Q object with the ones remaining in the list for item in queries: query |= item # Query the model Article.objects.filter(query) 

为了构build更复杂的查询,还可以select使用内置的Q()对象的常量Q.OR和Q.AND以及add()方法,如下所示:

 list = [1, 2, 3] # it gets a bit more complicated if we want to dynamically build # OR queries with dynamic/unknown db field keys, let's say with a list # of db fields that can change like the following # list_with_strings = ['dbfield1', 'dbfield2', 'dbfield3'] # init our q objects variable to use .add() on it q_objects = Q() # loop trough the list and create an OR condition for each item for item in list: q_objects.add(Q(pk=item), Q.OR) # for our list_with_strings we can do the following # q_objects.add(Q(**{item: 1}), Q.OR) queryset = Article.objects.filter(q_objects) # sometimes the following is helpful for debugging (returns the SQL statement) # print queryset.query 

使用python的reduce函数编写Dave Webb的答案的一种较短的方法:

 # For Python 3 only from functools import reduce values = [1,2,3] # Turn list of values into one big Q objects query = reduce(lambda q,value: q|Q(pk=value), values, Q()) # Query the model Article.objects.filter(query) 
 from functools import reduce from operator import or_ from django.db.models import Q values = [1, 2, 3] query = reduce(or_, (Q(pk=x) for x in values)) 

也许最好使用sql IN语句。

 Article.objects.filter(id__in=[1, 2, 3]) 

请参阅queryset api参考 。

如果你真的需要dynamic逻辑查询,你可以做这样的事情(丑+未testing):

 query = Q(field=1) for cond in (2, 3): query = query | Q(field=cond) Article.objects.filter(query) 

看文档 :

 >>> Blog.objects.in_bulk([1]) {1: <Blog: Beatles Blog>} >>> Blog.objects.in_bulk([1, 2]) {1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>} >>> Blog.objects.in_bulk([]) {} 

请注意,这种方法只适用于主键查找,但这似乎是你想要做的。

所以你想要的是:

 Article.objects.in_bulk([1, 2, 3]) 

您可以使用| =运算符以编程方式更新使用Q对象的查询。

如果我们想以编程方式设置我们想要查询的数据库字段:

 import operator questions = [('question__contains', 'test'), ('question__gt', 23 )] q_list = [Q(x) for x in questions] Poll.objects.filter(reduce(operator.or_, q_list)) 

这一个是为dynamicpk列表:

 pk_list = qs.values_list('pk', flat=True) # ie [] or [1, 2, 3] if len(pk_list) == 0: Article.objects.none() else: q = None for pk in pk_list: if q is None: q = Q(pk=pk) else: q = q | Q(pk=pk) Article.objects.filter(q) 

直到最近我还没有意识到的另一个选项 – QuerySet也覆盖了&|~等等,运营商。 另一个答案是OR Q对象是这个问题的更好的解决scheme,但是为了利益/争论,你可以这样做:

 id_list = [1, 2, 3] q = Article.objects.filter(pk=id_list[0]) for i in id_list[1:]: q |= Article.objects.filter(pk=i) 

str(q.query)将使用WHERE子句中的所有filter返回一个查询。

简单..
from django.db.models import Q import you model args =(Q(visibility = 1)|(Q(visibility = 0)&Q(user = self.user)))#Tuple parameters = {} #dic order ='create_at 'limit = 10

 Models.objects.filter(*args,**parameters).order_by(order)[:limit]