Я пытаюсь создать поиск для сайта Django, который я строю, и в этом поиске я ищу в 3 разных моделях. И чтобы получить нумерацию страниц в списке результатов поиска, я хотел бы использовать общее представление object_list для отображения результатов. Но для этого мне нужно объединить 3 набора запросов в один.
Как я могу это сделать? Я пробовал это:
result_list = []
page_list = Page.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term))
article_list = Article.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
post_list = Post.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
for x in page_list:
result_list.append(x)
for x in article_list:
result_list.append(x)
for x in post_list:
result_list.append(x)
return object_list(
request,
queryset=result_list,
template_object_name='result',
paginate_by=10,
extra_context={
'search_term': search_term},
template_name="search/result_list.html")
Но это не работает. Я получаю сообщение об ошибке, когда пытаюсь использовать этот список в общем представлении. В списке отсутствует атрибут clone.
Кто-нибудь знает, как я могу объединить три списка page_list
, article_list
и post_list
?
django
search
django-queryset
django-q
espenhogbakk
источник
источник
union
.Ответы:
Объединение наборов запросов в список - самый простой подход. Если база данных будет обработана для всех наборов запросов в любом случае (например, потому что результат должен быть отсортирован), это не добавит дополнительных затрат.
Использование
itertools.chain
выполняется быстрее, чем зацикливание каждого списка и добавление элементов один за другим, посколькуitertools
реализовано в C. Кроме того, оно потребляет меньше памяти, чем преобразование каждого набора запросов в список перед объединением.Теперь можно отсортировать итоговый список, например, по дате (как было запрошено в комментарии hasen j к другому ответу).
sorted()
Функция удобно принимает генератор и возвращает список:Если вы используете Python 2.4 или более позднюю версию, вы можете использовать
attrgetter
вместо лямбды. Я помню, что читал о том, что это быстрее, но я не увидел заметной разницы в скорости для списка из миллиона предметов.источник
from itertools import groupby
unique_results = [rows.next() for (key, rows) in groupby(result_list, key=lambda obj: obj.id)]
'list' object has no attribute 'complex_filter'
Попробуй это:
Он сохраняет все функции наборов запросов, что хорошо, если вы хотите,
order_by
или аналогичные.Обратите внимание: это не работает на наборах запросов от двух разных моделей.
источник
|
оператор объединения множеств, а не побитовое ИЛИ.Связанные, для смешивания querysets из одной и той же модели, или для аналогичных полей из нескольких моделей, начиная с Django 1.11
qs.union()
метод также доступен:https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.query.QuerySet.union
источник
Вы можете использовать
QuerySetChain
класс ниже. При использовании его с пагинатором Django он должен попадать в базу данных только сCOUNT(*)
запросами для всех наборовSELECT()
запросов, а запросы - только для тех наборов запросов, записи которых отображаются на текущей странице.Обратите внимание, что вам нужно указать
template_name=
, используете лиQuerySetChain
со стандартными представлениями, даже если все связанные наборы запросов используют одну и ту же модель.В вашем примере использование будет:
Затем используйте
matches
с пагинатором, как вы использовалиresult_list
в своем примере.itertools
Модуль был введен в Python 2.3, поэтому она должна быть доступна во всех версиях Python Django работает под управлением .источник
Большим недостатком вашего текущего подхода является его неэффективность с большими наборами результатов поиска, так как вы должны каждый раз извлекать весь набор результатов из базы данных, даже если вы намереваетесь отображать только одну страницу результатов.
Чтобы вытащить только те объекты, которые вам действительно нужны, из базы данных, вы должны использовать нумерацию страниц в QuerySet, а не в списке. Если вы сделаете это, Django фактически нарезает QuerySet перед выполнением запроса, поэтому SQL-запрос будет использовать OFFSET и LIMIT, чтобы получить только те записи, которые вы фактически отобразите. Но вы не можете сделать это, если не можете как-то втиснуть свой поиск в один запрос.
Учитывая, что все три ваши модели имеют поля title и body, почему бы не использовать наследование моделей ? Просто имейте все три модели, наследующие от общего предка, у которого есть заголовок и тело, и выполняйте поиск как единственный запрос на модели предка.
источник
Если вы хотите связать много наборов запросов, попробуйте это:
где: docs это список наборов запросов
источник
Цитируется с https://groups.google.com/forum/#!topic/django-users/6wUNuJa4jVw . Смотри Алекс Гейнор
источник
Это может быть достигнуто двумя способами.
1-й способ сделать это
Используйте оператор объединения для набора запросов
|
для объединения двух наборов запросов. Если оба набора запросов принадлежат одной и той же модели / одной модели, можно объединить наборы запросов с помощью оператора объединения.Для примера
2-й способ сделать это
Еще один способ выполнения операции объединения двух наборов запросов - использование цепной функции itertools .
источник
Требования:
Django==2.0.2
,django-querysetsequence==0.8
В случае, если вы хотите объединить
querysets
и все еще выйти сQuerySet
, вы можете проверить django-queryset-sequence .Но одно замечание по этому поводу. Это только два,
querysets
как аргумент. Но с Pythonreduce
вы всегда можете применить его к несколькимqueryset
s.И это все. Ниже приведена ситуация, с которой я столкнулся, и как я работал
list comprehension
,reduce
иdjango-queryset-sequence
источник
Book.objects.filter(owner__mentor=mentor)
не делает то же самое? Я не уверен, что это правильный вариант использования. Я думаю, чтоBook
может потребоваться несколькоowner
s, прежде чем вам нужно будет делать что-то подобное.вот идея ... просто вытяните по одной полной странице результатов из каждого из трех, а затем отбросьте 20 наименее полезных ... это исключает большие наборы запросов и таким образом вы жертвуете лишь небольшой производительностью вместо большого количества
источник
Это сделает работу без использования каких-либо других библиотек
источник
Эта рекурсивная функция объединяет массив наборов запросов в один набор запросов.
источник