Memeriksa queryset kosong di Django


183

Apa idiom yang disarankan untuk memeriksa apakah permintaan mengembalikan hasil?
Contoh:

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

Saya kira ada beberapa cara berbeda untuk memeriksa ini, tetapi saya ingin tahu bagaimana seorang pengguna Django yang berpengalaman akan melakukannya. Sebagian besar contoh dalam dokumen hanya mengabaikan kasus di mana tidak ada yang ditemukan ...

Jawaban:


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

5
Ini tampaknya lebih disukai dalam dokumentasi juga, misalnya: docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7
Wtower

1
@ Power Kode yang Anda rujuk memiliki untuk kontrak untuk meningkatkan 404 jika ekspresi penyaringan tidak mencapai catatan apa pun atau untuk menghasilkan listhasil jika ada catatan. Kode di sana akan mengenai database hanya sekali. Jika mereka menggunakan exist()atau count()untuk pertama memeriksa apakah akan ada catatan yang dikembalikan, mereka akan memukul database dua kali (satu kali untuk memeriksa, satu kali untuk mendapatkan catatan). Ini adalah situasi khusus. Itu tidak berarti bahwa dalam kasus umum , metode yang lebih disukai untuk mengetahui apakah permintaan akan mengembalikan catatan adalah menggunakan doif queryset:...
Louis

1
@Louis kode yang saya rujuk hanyalah contoh yang berisi garis if not my_objects:untuk menunjukkan bahwa ini adalah cara mereka melakukannya dalam dokumen. Semua yang lain sama sekali tidak relevan jadi saya tidak mengerti maksud Anda. Mereka juga dapat membuat seribu pertanyaan dan itu masih akan sama sekali tidak relevan karena ini bukan poin dari jawaban ini, yang saya jelaskan dengan persetujuan saya.
Wtower

1
@Wtower Itu hanya penjelasan tentang cara get_object_or_404kerjanya, bukan cara yang disukai untuk memeriksa apakah ada elemen dalam queryset. Melakukan daftar () pada queryset akan mengambil setiap objek pada queryset, yang akan lebih buruk daripada meminta dua kali jika ada banyak baris yang dikembalikan.
minmaxavg

1
Untuk jawaban yang lebih rinci, lihat jawaban @ leonid-shvechikov di bawah ini: menggunakan .exists()lebih efisien jika qs tidak akan dievaluasi.
Persaingan

191

Sejak versi 1.2, Django memiliki QuerySet. ada () metode yang paling efisien:

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

Tetapi jika Anda akan mengevaluasi QuerySet, lebih baik menggunakan:

if orgs:
   ...

Untuk informasi lebih lanjut baca dokumentasi QuerySet.exists () .


.exists () hanya untuk .filter (), apakah ada sesuatu untuk .get ()?
roll

.gettidak mengembalikan queryset. Ini mengembalikan suatu objek. Jadi google untuk itu
Aseem

Ini hanya terasa lebih efisien jika Anda memiliki QuerySet besar: docs.djangoproject.com/en/2.1/ref/models/querysets/#exists
Nathan Jones

16

Jika Anda memiliki banyak objek, ini bisa (kadang-kadang) jauh lebih cepat:

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

Pada proyek yang saya kerjakan dengan database besar, not orgs400+ ms dan orgs.count()250ms. Dalam kasus penggunaan saya yang paling umum (yang ada hasilnya), teknik ini sering menurunkannya hingga di bawah 20 ms. (Satu kasus yang saya temukan, itu 6.)

Bisa jadi lebih lama, tentu saja, tergantung pada seberapa jauh database harus mencari untuk menemukan hasilnya. Atau bahkan lebih cepat, jika ia menemukannya dengan cepat; YMMV.

EDIT: Ini akan sering lebih lambat daripada orgs.count()jika hasilnya tidak ditemukan, terutama jika kondisi yang Anda filter jarang terjadi; sebagai hasilnya, ini sangat berguna dalam fungsi tampilan di mana Anda perlu memastikan tampilan ada atau melempar Http404. (Di mana, orang akan berharap, orang-orang meminta URL yang ada lebih sering daripada tidak.)


10

Untuk memeriksa kekosongan queryset:

if orgs.exists():
    # Do something

atau Anda dapat memeriksa item pertama dalam queryset, jika tidak ada item itu akan kembali None:

if orgs.first():
    # Do something

7
if orgs.exists()ditutupi oleh jawaban yang diberikan sekitar 5 tahun sebelum ini. Satu-satunya jawaban yang dibawa ke meja yang mungkin baru adalah if orgs.first(). (Bahkan ini masih bisa diperdebatkan: apakah ini jauh berbeda dengan melakukan yang orgs[0] disarankan sekitar 5 tahun yang lalu juga?) Anda harus mengembangkan bagian dari jawaban itu: kapan seseorang ingin melakukan ini daripada solusi lain yang diusulkan sebelumnya?
Louis

9

Cara paling efisien (sebelum Django 1.2) adalah ini:

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

5
.exists () tampaknya lebih efisien
dzida

5
Kecuali bahwa .exists () ditambahkan beberapa bulan setelah komentar saya, dan Django 1.2 (yang memasukkan API) dirilis ~ 8 bulan kemudian. Namun terimakasih telah melakukan voting dan tidak repot untuk memeriksa fakta.
Bartosz

4
Maaf, saya menambahkan suntingan kecil ke jawaban Anda untuk membuatnya lebih akurat dan memberikan suara positif.
dzida

4

Saya tidak setuju dengan predikat itu

if not orgs:

Harus

if not orgs.count():

Saya mengalami masalah yang sama dengan hasil yang cukup besar (~ hasil 150k). Operator tidak kelebihan beban di QuerySet, jadi hasilnya sebenarnya dibongkar sebagai daftar sebelum pemeriksaan dilakukan. Dalam kasus saya waktu eksekusi turun tiga pesanan.


6
__nonzero__ sudah kelebihan beban di QuerySet. Jika hasilnya tidak di-cache (itu tidak pernah pada penggunaan queryset pertama) perilaku __nonzero__ adalah untuk beralih pada semua elemen dalam queryset. Ini sangat buruk jika setnya besar.
hedleyroos

0

Anda juga bisa menggunakan ini:

if(not(orgs)): #if orgs is empty else: #if orgs is not empty

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.