How to chain Django querysets preserving individual order
I'd like to append or chain several Querysets in Django, preserving the order of each one (not the result). I'm using a third-party library to paginate the result, and it only accepts lists or querysets. I've tried these options:
Queryset join: Doesn't preserve ordering in individual querysets, so I can't use this.
result = queryset_1 | queryset_2
Using itertools: Calling
list() on the chain object actually evaluates the querysets and this could cause a lot of overhead. Doesn't it?
result = list(itertools.chain(queryset_1, queryset_2))
How do you think I should go?
Here is better solution as for me: (It prevent duplicates)
q1 = Q(...) q2 = Q(...) q3 = Q(...) qs = Model.objects.filter(q1 | q2 | q3) .annotate( search_type_ordering=Case( When(q1, then=Value(2)), When(q2, then=Value(1)), When(q3, then=Value(0)), default=Value(-1), output_field=IntegerField(), ) ).order_by('-search_type_ordering', ...)
Django : Create a QuerySet from a list, preserving order, Mathieu Leplatre · Dev · Personal · Sys · Ux · Django : Create a QuerySet from a list, preserving order. # Import QuerySetSequence from queryset_sequence import QuerySetSequence # Create QuerySets you want to chain. from.models import SomeModel, OtherModel # Chain them together. query = QuerySetSequence(SomeModel.objects.all(), OtherModel.objects.all()) # Use query as if it were a QuerySet! E.g. in a ListView.
If the querysets are of different models, you have to evaluate them to lists and then you can just append:
result = list(queryset_1) + list(queryset_2)
If they are the same model, you should combine the queries using the Q object and 'order_by("queryset_1 field", "queryset_2 field")'.
The right answer largely depends on why you want to combine these and how you are going to use the results.
5. How to do union of two querysets from same or different models , def __iter__(self): queryset = self.queryset db = queryset.db compiler require an alias") kwargs[arg.default_alias] = arg query = self.query.chain() for (alias, *args, **kwargs): """ Perform the query and return a single object matching the given To preserve ordering of args for arg in args: # The default_alias property may Since Django 2.2, these queries issue a deprecation warning indicating to add an explicit order_by() to the queryset to silence the warning. Fields that are mentioned in the order_by() part of a queryset (or which are used in the default ordering on a model) are used when selecting the output data, even if they are not otherwise specified in
So, inspired by Peter's answer this is what I did in my project (Django 2.2 by the way):
from django.db import models from .models import MyModel # Add an extra field to each query with a constant value queryset_0 = MyModel.objects.annotate( qs_order=models.Value(0, models.IntegerField()) # Each constant should basically act as the position where we want the # queryset to stay queryset_1 = MyModel.objects.annotate( qs_order=models.Value(1, models.IntegerField()) [...] queryset_n = MyModel.objects.annotate( qs_order=models.Value(n, models.IntegerField()) # Finally, I ordered the union result by that extra field. union = queryset_0.union( queryset_1, queryset_2, [...], queryset_n).order_by('qs_order')
With this, I could order the resulting union as I wanted without changing any private attribute while only evaluating the querysets once.
Combine Two Querysets in Django (with different models), Use QuerySet.explain() to understand how specific QuerySet s are executed by Adding an index to your database may help to improve ordering performance. # Import QuerySetSequence from queryset_sequence import QuerySetSequence # Create QuerySets you want to chain. from.models import SomeModel, OtherModel # Chain them together. query = QuerySetSequence(SomeModel.objects.all(), OtherModel.objects.all()) # Use query as if it were a QuerySet! E.g. in a ListView.
For Django 1.11 (released on April 4, 2017) use union() for this, documentation here:
Here is the Version 2.1 link to this: https://docs.djangoproject.com/en/2.1/ref/models/querysets/#union
django.db.models.query | Django documentation, single query set out of two or more query sets? RS Taken from http://www.djangoproject.com/documentation/models/basic/ > you can Django : Create a QuerySet from a list, preserving order. Fri 08 November 2013 By Mathieu Leplatre. In Dev. tags: django. I thought it would be an easy one, but found myself lost with 34 opened tabs on stackoverflow The problem : keep it ordered.
I'm not 100% sure this solution works in every possible case, but it looks like the result is the union of two QuerySets (on the same model) preserving the order of the first one:
union = qset1.union(qset2) union.query.extra_order_by = qset1.query.extra_order_by union.query.order_by = qset1.query.order_by union.query.default_ordering = qset1.query.default_ordering union.query.get_meta().ordering = qset1.query.get_meta().ordering
I did not test it extensively, so before you use that code in production, make sure it behaves like expected.
Database access optimization | Django documentation, Django model queries classified by SQL keywords. reverse() method that inverts the order of a list, except it's designed to operate on Django QuerySet from coffeehouse.items.models import Item, Drink from itertools import chain Storing this type of aggregate information as individual Django model fields is redundant In this chapter, we dug much deeper into Django’s models, exploring the essentials of Django’s models. We looked at the common data management functions built into Django. We also learned about the common model methods that return QuerySets and those that don’t, model field lookups, aggregate functions, and building complex queries.
How do you concatenate two querysets?, The Django ORM is an invaluable tool for querying your data. a technique for extending Django querysets with methods specific to your models. As long as the encapsulation preserves the original interface, the calling You could just have your function return a queryset, and chain things to the result. How to chain Django requests by preserving the individual order I'd like to append or chain several Querysets in Django, preserving the order of each one (not the result). I'm using a third-party library to paginate the result, and it only accepts lists or querysets.
Django model queries by SQL keyword, Here are some pieces of advice for working with Django models. Preferable attributes and methods order in a model (an empty string between the points). Storing many files in one folder means the file system will search for the needed file more If you want to use this method in chain with others queryset methods,. The Django ORM is an invaluable tool for querying your data. However, as a generic tool, it's often not a clean fit. This article describes a technique for extending Django querysets with methods specific to your models.
Using Querysets to Compartmentalize Business Logic into ,