Reputation: 9400
I have a table 'tickets' with the following columns
When I'll do a SELECT *
I want the rows with status = 4
at the top, the other records will follow them. It can be achieved by the following query:
select * from tickets order by status=4 DESC
Can this query be executed through Django ORM? What parameters should be passed to the QuerySet.order_by()
method?
Upvotes: 26
Views: 10845
Reputation: 21
You can use simple a .annotate()
to add a True or False value for any given condition. In this case status = 4
is the first order_by
parameter, but it could be combined with any additional conditions.
from django.db.models import Q
tickets = Tickets.objects.all() ## Or .filter(**Your ciriteria**)
tickets = tickets.annotate(
priority1=Q(status=4),
priority2=Q(**Some Other Condition**),
[...]
)
tickets = tickets.order_by("-priority1", "-priority2", [...])
Upvotes: 2
Reputation: 378
For those in need just like me that stumbled on this now and are using newer versions of Django
from django.db.models import Case, When
Ticket.objects.annotate(
relevancy=Case(
When(status=4, then=1),
When(status=3, then=2),
When(status=2, then=3),
output_field=IntegerField()
)
).order_by('-relevancy')
Using Count() will return 1 or 0 depending if your case was found or not. Not ideal if ordering by a couple of status
Upvotes: 10
Reputation: 2078
I did this while using PostgresSql with django.
from django.db.models import Case, Count, When
Ticket.objects.annotate(
relevancy=Count(Case(When(status=4, then=1)))
).order_by('-relevancy')
It will return all objects from Ticket, but tickets with status = 4 will be at the beginning.
Hope someone will find it useful.
Upvotes: 16
Reputation: 24823
q = Ticket.objects.extra(select={'is_top': "status = 4"})
q = q.extra(order_by = ['-is_top'])
Upvotes: 25