How to dynamically compose an OR query filter in D

2019-02-27 12:28发布

From an example you can see a multiple OR query filter:

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

For example, this results in:

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

However, I want to create this query filter from a list. How to do that?

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

12条回答
Emotional °昔
2楼-- · 2019-02-27 12:30
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))
查看更多
Luminary・发光体
3楼-- · 2019-02-27 12:31

To build more complex queries there is also the option to use built in Q() object's constants Q.OR and Q.AND together with the add() method like so:

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
查看更多
看我几分像从前
4楼-- · 2019-02-27 12:31

This one is for dynamic pk list:

pk_list = qs.values_list('pk', flat=True)  # i.e [] 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)
查看更多
一纸荒年 Trace。
5楼-- · 2019-02-27 12:32

See the docs:

>>> 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([])
{}

Note that this method only works for primary key lookups, but that seems to be what you're trying to do.

So what you want is:

Article.objects.in_bulk([1, 2, 3])
查看更多
迷人小祖宗
6楼-- · 2019-02-27 12:32

You can use the |= operator to programmatically update a query using Q objects.

查看更多
倾城 Initia
7楼-- · 2019-02-27 12:36

You could chain your queries as follows:

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)
查看更多
登录 后发表回答