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.