If you’ve ever tried to concatenating two or more querysets from different models (i.e. combined = queryset1 | queryset2), you’ve hit this lovely error:
Cannot combine queries on two different base models.
The solution to this is to use itertools.
from itertools import chain | |
result_list = list(chain(queryset1, queryset2)) |
This allows you to not only combine the querysets into a single iterable, but it also allows you to sort the entire set by a shared field such as the date created:
from itertools import chain | |
from operator import attrgetter | |
# ascending oreder | |
result_list = sorted( | |
chain(queryset1, queryset2), | |
key=attrgetter('date_created')) | |
# descending order | |
result_list = sorted( | |
chain(queryset1, queryset2), | |
key=attrgetter('date_created'), | |
reverse=True) |
Thanks, It worked like a charm. Also you can add info about how to sort in descending order
Simply add reverse=True to the sorted method. I’ve updated the gist with an example.
Good article. Hopefully people will read this and realize Django is just Python, and be more pythonic when writing Django code.
Thanks
How would the front end code look to display the required fields from all the chained models in the front end templates?
Front-end code remains unchanged from how you would normally display fields from a model.
{{ mymodel.field }}
Is there a generic CBV that could handle these chained querySets? Can’t figure out how to unwrap these things.
Nice article, it’s helped a lot to solve my problem. thanks
hello man! I used chain to combine two different query set, but the problem I am having is that I can not sort or filter using the slug. it seems chain does not allow .object.get(slug)
def sport_list(request, slug):
travels= Travel.objects.all().order_by(‘-date’)
nutritions= Nutrition.objects.all().order_by(‘-date’)
sports= Sport.objects.all().order_by(‘-date’)
sportas = chain(travels, nutritions, sports)
newone = sportas.object.get(slug)