Apakah ada fungsi Django yang akan membiarkan saya mendapatkan objek dari database, atau None jika tidak ada yang cocok?
Saat ini saya menggunakan sesuatu seperti:
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Tapi itu tidak terlalu jelas, dan berantakan untuk dimiliki di mana-mana.
len(foo)
buruk : " Catatan: Jangan gunakan len () di QuerySets jika semua yang ingin Anda lakukan adalah menentukan jumlah record dalam set. Jauh lebih efisien untuk menangani hitungan di tingkat database, menggunakan SQL SELECT COUNT (), dan Django menyediakan metode count () tepat untuk alasan ini. ". Ditulis ulang:foo = foo[0] if foo.exists() else None
first()
: PJawaban:
Dalam Django 1.6 Anda dapat menggunakan
first()
metode Queryset. Ini mengembalikan objek pertama yang cocok dengan queryset, atau None jika tidak ada objek yang cocok.Pemakaian:
sumber
MultipleObjectsReturned()
tidak dimunculkan, seperti yang didokumentasikan di sini . Anda dapat menemukan jawaban yang lebih baik di sinifirst()
karya persis seperti rasa untuk. Ini mengembalikan objek pertama dalam hasil kueri dan tidak peduli jika beberapa hasil ditemukan. Jika Anda perlu memeriksa beberapa objek yang dikembalikan, Anda harus menggunakan.get()
sebagai gantinya..get()
tidak sesuai dengan kebutuhannya. Jawaban yang benar untuk pertanyaan ini dapat ditemukan di bawah oleh @kaapstorm, dan jelas merupakan jawaban yang lebih cocok. Menyalahgunakanfilter()
cara ini dapat menyebabkan konsekuensi yang tidak terduga, sesuatu yang mungkin tidak disadari oleh OP (kecuali saya melewatkan sesuatu di sini)MultipleObjectsReturned()
. Jika hasil yang dikembalikan tidak diharapkan mengembalikan banyak objek, maka itu tidak boleh diperlakukan seperti itu. Ada perdebatan panjang tentang ini di siniAda dua cara untuk melakukan ini;
Atau Anda bisa menggunakan pembungkus:
Sebut saja seperti ini
sumber
queryset
metode apa pun untuk melakukan ini sebelum 1.6! Tetapi untuk konstruksi ini - itu hanya kikuk. Ini tidak "jahat" karena beberapa penulis tutorial bahasa favorit Anda mengatakannya. Coba google: "minta maaf daripada izin".get
Metode ini tidak seharusnya kembaliNone
, jadi pengecualian masuk akal. Anda seharusnya menggunakannya jika Anda yakin objek akan ada di sana / objek "seharusnya" ada di sana. Juga menggunakan pengecualian seperti ini dianggap 'oke' karena, yah, itu masuk akal. Anda menginginkanget
dengan kontrak yang berbeda, sehingga Anda menangkap pengecualian dan menahannya, yang merupakan perubahan yang Anda cari.Untuk menambahkan beberapa kode contoh ke jawaban sorki (saya akan menambahkan ini sebagai komentar, tetapi ini adalah posting pertama saya, dan saya tidak memiliki cukup reputasi untuk meninggalkan komentar), saya menerapkan manajer kustom get_or_none seperti ini:
Dan sekarang saya bisa melakukan ini:
sumber
Anda juga dapat mencoba menggunakan django mengganggu (ini memiliki fungsi lain yang berguna!)
instal dengan:
sumber
Berikan Foo manajer kustomnya . Ini cukup mudah - cukup letakkan kode Anda ke dalam fungsi di pengelola khusus, setel pengelola khusus dalam model Anda dan panggil dengan
Foo.objects.your_new_func(...)
.Jika Anda memerlukan fungsi generik (untuk menggunakannya pada model apa pun tidak hanya dengan custom manager) tulis sendiri dan letakkan di suatu tempat di jalur python Anda dan impor, tidak berantakan lagi.
sumber
Baik melakukannya melalui manajer atau fungsi generik, Anda mungkin juga ingin menangkap 'MultipleObjectsReturned' dalam pernyataan TRY, karena fungsi get () akan menaikkannya jika kwarg Anda mengambil lebih dari satu objek.
Membangun dari fungsi generik:
dan di manajer:
sumber
Berikut adalah variasi pada fungsi helper yang memungkinkan Anda untuk meneruskan sebuah
QuerySet
instance secara opsional , jika Anda ingin mendapatkan objek unik (jika ada) dari queryset selainall
queryset objek model (misalnya dari subset item anak milik a contoh induk):Ini dapat digunakan dengan dua cara, misalnya:
obj = get_unique_or_none(Model, *args, **kwargs)
seperti yang telah dibahas sebelumnyaobj = get_unique_or_none(Model, parent.children, *args, **kwargs)
sumber
Saya pikir dalam banyak kasus Anda hanya dapat menggunakan:
Hanya jika tidak penting bahwa entri baru akan ditambahkan dalam tabel Foo (kolom lain akan memiliki nilai Tidak Ada / default)
sumber