Django, belirli bir sırayla id dizisinden bir QuerySet alır


84

İşte senin için hızlı bir tane:

Bir QuerySet (veya gerekirse dizi) döndürmek için kullanmak istediğim kimliklerin bir listesi var, ancak bu sırayı korumak istiyorum.

Teşekkürler

Yanıtlar:


72

Veritabanı düzeyinde bu belirli sırayı uygulayabileceğinizi sanmıyorum, bu yüzden bunu python'da yapmanız gerekir.

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]

Bu, anahtar olarak kimliklerine sahip nesnelerin bir sözlüğünü oluşturur, böylece sıralı liste oluştururken kolayca geri çağrılabilirler.



3
Bunu yaparken sonucu bellekte depolayacağınız için büyük sorgulara dikkat edin.
JJ.

14
Sözlüğü kendiniz oluşturmak yerine, sorgu kümeleri in_bulk () yöntemini kullanabilir misiniz?
Matt Austin

Bununla ilgili sorun, id_list'teki bir nesne yoksa, bir hata atacak olmasıdır.
madprops

Neden dikte anlamayı kullanmıyorsunuz?
wieczorek1990

186

Django 1.8'den beri şunları yapabilirsiniz:

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)

16
En iyi yanıt, aslında bir
sorgu kümesi

2
Hâlâ django'ların Case Whenküçümsenmediğini düşünüyorum !
Babu

distinct()Order_by case when clause ile kullanacağım ama hatayı aldım. herhangi bir destek lütfen.
elquimista

SELECT DISTINCT ON expressions must match initial ORDER BY expressions- işte hata mesajı
elquimista

1
Bu seçilen cevap olmalıydı.
Subangkar KrS

28

Bunu in_bulk kullanarak yapmak istiyorsanız, aslında yukarıdaki iki yanıtı birleştirmeniz gerekir:

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

Aksi takdirde, sonuç, özel olarak sıralı bir liste yerine bir sözlük olacaktır.


1
Bu daha iyi bir cevap değil.
Tony

26

İşte bunu veritabanı düzeyinde yapmanın bir yolu. Şuradan yapıştırın: blog.mathieu-leplatre.info :

MySQL :

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

Django ile aynı:

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;

Django ile aynı:

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',))

Vay. Bu yoğun. Teşekkürler!
Dan Gayle

Bu cevap için teşekkürler.
Subangkar KrS

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

1
Lütfen bunun nasıl çalıştığını ve OP'nin problemini neden çözeceğini açıklayan bir metin ekleyin. Başkalarının anlamasına yardımcı olun.
APC

En iyi cevap. Teşekkürler!
webjunkie

İyi çalışıyor, ek bilgi kullanabilirdi
xtrinch

bu sadece sıralı idlist için çalışacaktır. Herhangi bir sırayla çalışıp çalışmayacağını onaylayabilir misin ... bana doğru gelmiyor.
Doogle
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.