Question Django obtient un QuerySet à partir du tableau des identifiants dans un ordre spécifique


Voici un rapide pour vous:

J'ai une liste d'identifiants que je veux utiliser pour retourner un QuerySet (ou un tableau si besoin est), mais je veux conserver cet ordre.

Merci


44
2018-02-06 23:12


origine


Réponses:


Je ne pense pas que vous puissiez appliquer cet ordre particulier au niveau de la base de données, vous devez donc le faire en python.

id_list = [1, 5, 7]
objects = Foo.objects.filter(id__in=id_list)

objects = dict([(obj.id, obj) for obj in objects])
sorted_objects = [objects[id] for id in id_list]

Cela crée un dictionnaire des objets avec leur identifiant comme clé, de sorte qu'ils peuvent être facilement récupérés lors de la construction de la liste triée.


48
2018-02-06 23:20



Depuis Django 1.8, vous pouvez faire:

from django.db.models import Case, When

pk_list = [10, 2, 1]
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pk_list)])
queryset = MyModel.objects.filter(pk__in=pk_list).order_by(preserved)

80
2018-06-06 00:57



Si vous voulez faire cela en utilisant in_bulk, vous devez fusionner les deux réponses ci-dessus:

id_list = [1, 5, 7]
objects = Foo.objects.in_bulk(id_list)
sorted_objects = [objects[id] for id in id_list]

Sinon, le résultat sera un dictionnaire plutôt qu'une liste spécialement ordonnée.


24
2017-12-12 01:50



Voici un moyen de le faire au niveau de la base de données. Copier coller de: blog.mathieu-leplatre.info  :

MySQL:

SELECT *
FROM theme
ORDER BY FIELD(`id`, 10, 2, 1);

Même avec Django:

pk_list = [10, 2, 1]
ordering = 'FIELD(`id`, %s)' % ','.join(str(id) for id in pk_list)
queryset = Theme.objects.filter(pk__in=[pk_list]).extra(
           select={'ordering': ordering}, order_by=('ordering',))

PostgreSQL:

SELECT *
FROM theme
ORDER BY
  CASE
    WHEN id=10 THEN 0
    WHEN id=2 THEN 1
    WHEN id=1 THEN 2
  END;

Même avec Django:

pk_list = [10, 2, 1]
clauses = ' '.join(['WHEN id=%s THEN %s' % (pk, i) for i, pk in enumerate(pk_list)])
ordering = 'CASE %s END' % clauses
queryset = Theme.objects.filter(pk__in=pk_list).extra(
           select={'ordering': ordering}, order_by=('ordering',))

19
2017-08-25 06:55



id_list = [1, 5, 7]
objects = Foo.objects.filter(id__in=id_list)
sorted(objects, key=lambda i: id_list.index(i.pk))

8
2017-11-29 21:05