created on Oct. 31, 2012, 12:21 a.m. by Hevok & updated on Oct. 31, 2012, 12:21 a.m. by Hevok
Different querysets can be combined via this method:
.. sourcecode:: python
from itertools import chain
result_list = list(chain(entry_list, post_list, page_list))
This results can be further sorted by common attributes:
.. sourcecode:: python
result_list = sorted(
chain(entry_list, post_list, page_list),
key=lambda instance: instance.created)
Instead of lambda attrgetter
can be used:
.. sourcecode:: python
result_list = sorted(
chain(entry_list, post_list, page_list),
key=attrgetter('created')
If the querysets are from the same model the bitwise or operator comes in handy:
.. sourcecode:: python
matches = current_entries | new_entries | other_entries
An interesting approach is the usage of a QuerySetChain
class:
.. sourcecode:: python
class QuerySetChain(object):
"""Chains multiple querysets (possibly of different models) and behaves
as one queryset. Supports minimal methods needed for use with
django.core.paginator."""
def __init__(self, *subquerysets):
self.queryseys = 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, dx.stop or 1))
else:
return islice(self.__all(), ndx, ndx+1).next()
This class can be implemented for instance in such a way:
.. sourcecode:: python
entries = Entry.objects.filter(Q(title__icontains=cleaned_search_term) |
Q(text__icontains=cleaned_search_term) |
Q(tags__name__icontains=cleanded_search_term))
posts = Post.objects.filter(Q(title__icontains=cleaned_search_term) |
Q(text__icontains=cleaned_search_term) |
Q(tags___name__icontains=cleaned_search_term))
pages = Page.objects.filter(Q(title__icontains=cleaned_search_term) |
Q(text__icontains=cleaned_search_term) |
Q(tags__name__icontains=cleaned_search_term))
matches = QuerySetChain(entries, posts, pages)
matches
can then be used with the paginator like it would be used for
result_list
.
.. See also Chain multiple querysets into one
and Multiple querysets
.. _`Chain multiple querysets into one`: http://djangosnippets.org/snippets/1103/
.. _`Multiple querysets`: http://djangosnippets.org/snippets/1933/
Comment on This Data Unit