12👍
Since there exists Case
and When
in Django >= 1.11 you can do it in a more orm-like way keeping all the benefits of your queryset:
from django.db import models
order = ['b', 'a', 'z', 'x', 'c']
_whens = []
for sort_index, value in enumerate(order):
_whens.append(
models.When(my_field=value, then=sort_index)
)
qs = MyModel.objects.annotate(
_sort_index=models.Case(
*_whens,
output_field=models.IntegerField()
)
)
qs.order_by('_sort_index')
This will generate something like this:
from django.db import models
order = ['b', 'a', 'z', 'x', 'c']
qs = MyModel.objects.annotate(
_sort_index=models.Case(
models.When(my_field='b', then=0),
models.When(my_field='a', then=1),
models.When(my_field='z', then=2),
models.When(my_field='x', then=3),
models.When(my_field='c', then=4),
output_field=models.IntegerField()
)
).order_by('_sort_index')
I would suggest to use this only with a small amount of list-items because it blows up the database-query.
https://docs.djangoproject.com/ko/1.11/ref/models/conditional-expressions/#case
5👍
No. There is no way to do what you want short of some contrived mechanism like:
qs = m.objects.filter(id__in=[3,1,8])
qs_sorted = list()
for id in [3,1,8]:
qs_sorted.append(qs.get(id=id))
You’d need to throw some exception handling in there as well, just in case one of the specified ids wasn’t actually returned.
The negatives are that this will effectively negate the lazy loading of queryset. In fact, it’s very likely to generate multiple DB queries (haven’t tested that though). Also, you end up with a normal python list instead of a queryset, so no more filtering is possible.
3👍
See Ordering by the order of values in a SQL IN() clause – you’d need to drop down to a raw queryset and it’d be database specific.
If you’re using MySQL for example you should be able to do a
Model.objects.raw('select * from myapp_model where id in (3,1,8) order by field(id,3,1,8)')
- How to get values of all object fields in Django?
- Is there a Django template tag that lets me set a context variable?
- Python + Django + VirtualEnv + Windows
2👍
Most of your sorting options assume there is an order to what you are sorting. If you can define the order you can use order_by
and a field on your model, or sorted
using python. If you want to just reorder things (with seemingly no logic) you could still probably use sorted
:
for id in [3,1,8]:
sorted(qs, key=lambda x: x.id == id)
- Django. ''The `actions` argument must be provided when calling `.as_view()` '' when I try to allow DELETE, PUT, ETC
- Gunicorn sync workers spawning processes
1👍
Maybe you can use order-by as zeekay mentioned.
If it is OK that your QuerSet will be turned into a list, then you can use something like this
sorted(queryset, key=lambda x: x.id)
1👍
Thank you all for your answers. I’v came up with another solution. It’s not the best one but is only needs to do one query to the database.
I have a list with the id’s I want ordered by my needs. Then I make the query and fill in a dictionary with the data and finally I traverse l picking up the objects in an ordered fashion.
l =[7,1,4]
p_dict = {}
p = Poi.objects.filter(id__in=l)
for i in p:
p_dict[i.id] = i
Using this I will use a lot of memory right? But I gain in accesses to the database.
@a-lee I will investigate your solution and try to tranform it to postgresql.
- Django HTML E-mail template doesn't load css in the e-mail
- Use a django built in filter in code (outside of a template)
- Django Admin + FORCE_SCRIPT_NAME + Login redirects incorrectly
- Load Balancing Multiple Django Webservers
-1👍
preserved = [Case(*[When(pk=pk, then=pos) for pos, pk in enumerate([3,1,8])])]
queryset.order_by(*preserved)
- Sometimes request.session.session_key is None
- "TemplateSyntaxError Invalid block tag: 'trans'" error in Django Templates
- Installed Virtualenv and activating virtualenv doesn't work
- Return image url in Django Rest Framework