Можно использовать QuerySetChain
класс ниже. При использовании его с paginator Django он должен только поразить базу данных COUNT(*)
запросы для всего querysets и SELECT()
запросы только для тех querysets, записи которых отображены на текущей странице.
Примечание, которое необходимо указать template_name=
при использовании QuerySetChain
с универсальными представлениями, даже если цепочечный querysets все использование та же модель.
from itertools import islice, chain
class QuerySetChain(object):
"""
Chains multiple subquerysets (possibly of different models) and behaves as
one queryset. Supports minimal methods needed for use with
django.core.paginator.
"""
def __init__(self, *subquerysets):
self.querysets = subquerysets
def count(self):
"""
Performs a .count() for all subquerysets and returns the number of
records as an integer.
"""
return sum(qs.count() for qs in self.querysets)
def _clone(self):
"Returns a clone of this queryset chain"
return self.__class__(*self.querysets)
def _all(self):
"Iterates records in all subquerysets"
return chain(*self.querysets)
def __getitem__(self, ndx):
"""
Retrieves an item or slice from the chained set of results from all
subquerysets.
"""
if type(ndx) is slice:
return list(islice(self._all(), ndx.start, ndx.stop, ndx.step or 1))
else:
return islice(self._all(), ndx, ndx+1).next()
В Вашем примере, использование было бы:
pages = Page.objects.filter(Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term))
articles = Article.objects.filter(Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
posts = Post.objects.filter(Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
matches = QuerySetChain(pages, articles, posts)
Затем использование matches
с paginator как Вы использовало result_list
в Вашем примере.
itertools
модуль был представлен в Python 2.3, таким образом, это должно быть доступно во всех версиях Python, Django работает.
Единственное использование, которое я могу придумать, было бы, если бы конструктору нужно было использовать универсальный объект во время его работы, но не сохранять этот объект после его завершения.
Например, :
<T> NonGeneric(T[] blank, List<T> list) {
// Sort that list
T[] array = list.toArray(blank);
Arrays.sort(array);
// Pull out the values as strings
this.list = new ArrayList<String>(array.length);
for (T value : array) {
this.list.add(value.toString());
}
}
Скорее всего, это просто то, что разработчики языка решили сделать на тот случай, если кто-то этого захочет, поскольку не было причин мешать людям это делать.