Как динамически составить фильтр или запрос в Django?
из примера вы можете увидеть несколько или запрос фильтра:
Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))
например, это:
[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]
тем не менее, я хочу создать этот фильтр запроса из списка. Как это сделать?
например [1, 2, 3] -> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))
12 ответов:
вы можете цепочку запросов следующим образом:
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)
для построения более сложных запросов есть также возможность использовать встроенные константы Q () объекта Q. или и Q. и вместе с 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:
# 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 в инструкции.
Article.objects.filter(id__in=[1, 2, 3])посмотреть queryset api reference.
Если вам действительно нужно делать запросы с динамической логикой, вы можете сделать что-то вроде этого (некрасиво + не проверено):
query = Q(field=1) for cond in (2, 3): query = query | Q(field=cond) Article.objects.filter(query)
посмотреть 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([]) {}обратите внимание, что этот метод работает только для поиска первичного ключа, но это, кажется, то, что вы пытаетесь сделать.
Так что вы хотите:
Article.objects.in_bulk([1, 2, 3])
в случае, если мы хотим программно установить, какое поле БД мы хотим запросить:
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))
используя решение с
reduceиor_оператор здесь как вы можете фильтровать по полям умножения.from functools import reduce from operator import or_ from django.db.models import Q filters = {'field1': [1, 2], 'field2': ['value', 'other_value']} qs = Article.objects.filter( reduce(or_, (Q(**{f'{k}__in': v}) for k, v in filters.items())) )п.С.
fЭто новый формат строки литерал aded в python3. 6
Это для динамического списка ПК:
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)
еще один вариант, о котором я не знал до недавнего времени -
QuerySetтакже переопределяет&,|,~, etc, операторы. Другие ответы, которые или Q объекты являются лучшим решением этого вопроса, но ради интереса / аргумента, вы можете сделать: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предложения.
легко..
из Джанго.децибел.модели импорт вопрос импорт вас модель параметр args = (м(видимость=1)|(м(видимость=0) и Q(пользователь=собственн.пользователь))) #Кортеж параметры={} #ОПК order = 'create_at' лимит = 10Models.objects.filter(*args,**parameters).order_by(order)[:limit]
Comments