Django'daki boş sorgu kümesini kontrol etme


183

Bir sorgunun sonuç döndürüp döndürmediğini kontrol etmek için önerilen deyim nedir?
Misal:

orgs = Organisation.objects.filter(name__iexact = 'Fjuk inc')
# If any results
    # Do this with the results without querying again.
# Else, do something else...

Bunu kontrol etmenin birkaç farklı yolu olduğunu düşünüyorum, ancak deneyimli bir Django kullanıcısının bunu nasıl yapacağını bilmek istiyorum. Dokümanlardaki çoğu örnek, hiçbir şeyin bulunmadığı durumu görmezden geliyor ...

Yanıtlar:


207
if not orgs:
    # Do this...
else:
    # Do that...

5
Bu, dokümantasyonda da tercih ediliyor gibi görünmektedir, örneğin: docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7
Wtower

1
@Wtower Filtreleme ifadesi herhangi bir kayda ulaşmazsa, sözleşme için 404'ü yükseltmek veya kayıtlar listvarsa sonucu üretmek için sözleşmeye aittir . Buradaki kod veritabanına yalnızca bir kez vuracaktır. Kullanırlarsa exist()veya count()ilk olarak kayıtların döndürülüp döndürülmeyeceğini kontrol ederlerse, veritabanına iki kez vururlardı (kontrol etmek için bir kez, kayıtları almak için bir kez). Bu özel bir durum. Bu o gerektirmez genel durumda , bir sorgu kayıtları döndürür olmadığını bilmek tercih edilen yöntem kullanımına doif queryset:...
Louis

1
@Louis, bahsettiğim kod if not my_objects:, dokümanlarda bu şekilde yapıldığını göstermek için bir satır içerdiğini gösteren bir örnektir . Diğer her şey tamamen alakasız, bu yüzden fikrinizi anlayamıyorum. Binlerce sorgu da yapabilirler ve bu tamamen ilgisiz olacaktır, çünkü bu cevabın amacı bu değil, aynı fikirdeyim.
Wtower

1
@Wtower Bu, nasıl çalıştığının bir açıklamasıdır , bir sorgu kümesinde herhangi bir öğenin var olup olmadığını kontrol etmenin tercih edilen bir yolu değildir . Bir queryset üzerinde list () yapmak, bir queryset üzerindeki her nesneyi getirecektir; bu, döndürülen çok sayıda satır varsa iki kez sorgulamaktan daha kötü olacaktır. get_object_or_404
minmaxavg

1
Daha ayrıntılı bir cevap için @ leonid-shvechikov'un cevabına bakınız: .exists()qs değerlendirilmeyecekse kullanmak daha verimlidir.
guival

191

1.2 sürümünden bu yana, Django QuerySet vardır. en verimli olan exist () yöntemi:

if orgs.exists():
    # Do this...
else:
    # Do that...

Ancak yine de QuerySet'i değerlendirecekseniz kullanmak daha iyidir:

if orgs:
   ...

Daha fazla bilgi için QuerySet.exists () belgelerini okuyun .


.exists () yalnızca .filter () içindir, .get () için bir şey var mı?
rulo

.getbir queryset döndürmez. Bir nesne döndürür. Bunun için google
Aseem

Büyük bir QuerySet'iniz varsa fark edilir derecede daha etkilidir: docs.djangoproject.com/en/2.1/ref/models/querysets/#exists
Nathan Jones

16

Çok sayıda nesneniz varsa, bu (bazen) çok daha hızlı olabilir:

try:
    orgs[0]
    # If you get here, it exists...
except IndexError:
    # Doesn't exist!

Büyük bir veritabanı üzerinde çalıştığım bir projede not orgs, 400+ ms ve orgs.count()250ms. En yaygın kullanım durumlarımda (sonuçların olduğu durumlarda), bu teknik genellikle 20 ms'nin altına düşer. (Bir dava buldum, 6 yaşındaydı.)

Tabii ki, veritabanının bir sonuç bulmak için ne kadar araması gerektiğine bağlı olarak, çok daha uzun olabilir. Ya da daha hızlı, eğer hızlı bir şekilde bulursa; YMMV.

DÜZENLEME: Bu genellikle sonuç bulunamadığından daha yavaş olacaktırorgs.count() , özellikle de filtre uyguladığınız durum nadirse; Sonuç olarak, görünümün var olduğundan emin olmanız veya Http404 atmanız gereken görünüm işlevlerinde özellikle kullanışlıdır. (İnsanlar, umarız ki, insanlar daha sık olmayan URL'leri ister.)


10

Bir sorgu kümesinin boşluğunu kontrol etmek için:

if orgs.exists():
    # Do something

ya da bir sorgu kümesindeki ilk öğeyi kontrol edebilirsiniz, yoksa, geri dönecektir None:

if orgs.first():
    # Do something

7
if orgs.exists()bu sorudan yaklaşık 5 yıl önce verilen bir yanıtla karşılandı . Bu cevabın belki de yeni olan masaya getirdiği tek şey if orgs.first(). (Bu bile tartışmalı: yaklaşık 5 yıl önce orgs[0] önerileni yapmaktan önemli ölçüde farklı mı?) Cevabın bu kısmını geliştirmelisiniz: daha önce önerilen diğer çözümler yerine ne zaman yapmak istersiniz ?
Louis

9

En etkili yol (django 1.2'den önce) şudur:

if orgs.count() == 0:
    # no results
else:
    # alrigh! let's continue...

5
.exists () daha da verimli görünüyor
dzida

5
Bunun dışında .exists () yorumumdan birkaç ay sonra eklendi ve Django 1.2 (bu API'yı içeren) ~ 8 ay sonra yayınlandı. Ancak aşağı oylama ve gerçekleri kontrol etmek için uğraşmadığınız için teşekkürler.
Bartosz

4
Maalesef cevabınıza daha doğru olması için küçük bir düzenleme ekledim ve olumlu oy kullandım.
dzida

4

Yüklem ile aynı fikirde değilim

if not orgs:

Olmalı

if not orgs.count():

Aynı sorunu oldukça büyük bir sonuç setiyle (~ 150 bin sonuç) yaşıyordum. İşleç QuerySet'e aşırı yüklenmediğinden, denetim yapılmadan önce sonuç aslında bir liste olarak açılır. Benim durumumda, yürütme süresi üç sipariş azaldı.


6
__nonzero__ zaten QuerySet'te aşırı yüklü. Sonuç önbelleğe alınmazsa (hiçbir zaman sorgu kümesinin ilk kullanımında değilse) __nonzero__ davranışı sorgu kümesindeki tüm öğeler üzerinde yineleme yapmaktır. Set büyükse bu çok kötü.
hedleyroos

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.