Memfilter untuk nama kosong atau NULL dalam queryset

463

Saya punya first_name, last_name& alias(opsional) yang perlu saya cari. Jadi, saya perlu permintaan untuk memberi saya semua nama yang memiliki set alias.

Hanya jika saya bisa melakukan:

Name.objects.filter(alias!="")

Jadi, apa yang setara dengan yang di atas?

un33k
sumber

Jawaban:

841

Anda bisa melakukan ini:

Name.objects.exclude(alias__isnull=True)

Jika Anda perlu mengecualikan nilai nol dan string kosong, cara yang disukai untuk melakukannya adalah dengan menyatukan kondisi seperti:

Name.objects.exclude(alias__isnull=True).exclude(alias__exact='')

Merangkai metode ini bersama-sama pada dasarnya memeriksa setiap kondisi secara independen: dalam contoh di atas, kami mengecualikan baris di mana aliasnull atau string kosong, sehingga Anda mendapatkan semua Nameobjek yang memiliki bidang tidak-nol, tidak-kosong alias. SQL yang dihasilkan akan terlihat seperti:

SELECT * FROM Name WHERE alias IS NOT NULL AND alias != ""

Anda juga dapat meneruskan beberapa argumen ke satu panggilan exclude, yang akan memastikan bahwa hanya objek yang memenuhi setiap kondisi yang dikecualikan:

Name.objects.exclude(some_field=True, other_field=True)

Di sini, baris di mana some_field dan other_field benar dikecualikan, jadi kami mendapatkan semua baris di mana kedua bidang tidak benar. Kode SQL yang dihasilkan akan terlihat sedikit seperti ini:

SELECT * FROM Name WHERE NOT (some_field = TRUE AND other_field = TRUE)

Atau, jika logika Anda lebih kompleks dari itu, Anda bisa menggunakan objek Q Django :

from django.db.models import Q
Name.objects.exclude(Q(alias__isnull=True) | Q(alias__exact=''))

Untuk info lebih lanjut lihat halaman ini dan halaman ini dalam dokumen Django.

Sebagai tambahan: Contoh SQL saya hanya analogi - kode SQL yang dihasilkan mungkin akan terlihat berbeda. Anda akan mendapatkan pemahaman yang lebih dalam tentang bagaimana pertanyaan Django bekerja dengan benar-benar melihat SQL yang mereka hasilkan.

Sasha Chedygov
sumber
5
Saya percaya bahwa hasil edit Anda salah: Filter rantai TIDAK secara otomatis membuat SQL OR(hanya dalam kasus ini), itu menghasilkan SQL AND. Lihat halaman ini untuk referensi: docs.djangoproject.com/en/dev/topics/db/queries/... Keuntungan dari chaining adalah Anda dapat mencampur excludedan filtermemodelkan kondisi kueri yang rumit. Jika Anda ingin memodelkan SQL nyata, ORAnda harus menggunakan objek Django Q: docs.djangoproject.com/en/dev/topics/db/queries/... Harap edit hasil edit Anda untuk mencerminkan hal ini, karena jawabannya sangat menyesatkan seperti apa adanya. .
shezi
1
@ Shezi: Maksud saya lebih sebagai analogi - Saya tidak bermaksud bahwa kode SQL yang sebenarnya dijamin untuk menggunakan ORuntuk memadukan kondisi. Saya akan mengedit jawaban saya untuk menjelaskan.
Sasha Chedygov
1
Ingatlah bahwa ada berbagai cara untuk mewakili logika ini - misalnya, NOT (A AND B)setara dengan NOT A OR NOT B. Saya pikir itu membuat hal-hal membingungkan bagi pengembang Django baru yang tahu SQL tetapi tidak terbiasa dengan ORM.
Sasha Chedygov
3
Saya tahu hukum De Morgan, dan inilah poin saya tepatnya: Contoh Anda hanya berfungsi karena dibutuhkan untuk mengubah ANDkueri pertama menjadi ORkarena Anda gunakan exclude. Dalam kasus umum, mungkin lebih tepat untuk menganggap chaining sebagai THEN, yaitu exclude(A) THEN exclude(B). Maaf tentang bahasa kasar di atas. Jawaban Anda benar-benar bagus, tetapi saya khawatir pengembang baru mengambil jawaban Anda terlalu umum.
shezi
2
@shezi: Cukup adil. Saya setuju bahwa lebih baik untuk memikirkannya dalam istilah Django dan bukan dalam istilah SQL, saya hanya berpikir bahwa mempresentasikan chaining dalam hal ANDdan ORmungkin berguna bagi seseorang yang datang ke Django dari latar belakang SQL. Untuk pemahaman yang lebih mendalam tentang Django, saya pikir para dokter melakukan pekerjaan yang lebih baik daripada yang saya bisa.
Sasha Chedygov
49
Name.objects.filter(alias__gt='',alias__isnull=False)
jbofill
sumber
2
Saya tidak yakin, tapi saya pikir alias__isnull=Falsekondisinya berlebihan. Jika bidang itu Nullpasti akan dikeluarkan oleh klausa pertama?
Bobble
Selain dari komentar / pertanyaan saya sebelumnya, saya pikir logika positif di sini lebih mudah diikuti daripada di beberapa jawaban lainnya.
Bobble
@Bobble yang akan tergantung pada implementasi database - pemesanan didelegasikan ke databse
wpercy
alias__gtadalah satu-satunya hal yang berfungsi untuk kolom tipe JSON di mana saya ingin mengecualikan string kosong dari JSON seperti {'something:''}. Jadi sintaks yang berfungsi adalah:jsoncolumnname__something__gt=''
bartgras
38

Pertama, dokumen Django sangat merekomendasikan untuk tidak menggunakan nilai NULL untuk bidang berbasis string seperti CharField atau TextField. Baca dokumentasi untuk penjelasan:

https://docs.djangoproject.com/en/dev/ref/models/fields/#null

Solusi: Anda juga dapat menyatukan metode di QuerySets, saya pikir. Coba ini:

Name.objects.exclude(alias__isnull=True).exclude(alias="")

Itu akan memberi Anda set yang Anda cari.

b3ng0
sumber
5

Dari Django 1.8,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)
Programmer Kimia
sumber
5
Ini seperti "sesuatu yang bisa Anda lakukan", bukan sesuatu yang harus Anda lakukan. Ini secara signifikan mekar kompleksitas permintaan lebih dari dua pemeriksaan sederhana.
Oli
3

Untuk menghindari kesalahan umum saat menggunakan exclude, ingat:

Anda tidak dapat menambahkan beberapa kondisi ke dalam blokir exclude ()filter . Untuk mengecualikan beberapa kondisi, Anda harus menggunakan beberapa mengecualikan ()

Contoh

Salah :

User.objects.filter (email='[email protected] '). Kecualikan (profile__nick_name =' ', profile__avt =' ')

Benar :

User.objects.filter (email='[email protected] '). Kecualikan (profile__nick_name =' '). Kecualikan (profile__avt =' ')

HoangYell
sumber
0

Anda cukup melakukan ini:

Name.objects.exclude(alias="").exclude(alias=None)

Benar-benar sesederhana itu. filterdigunakan untuk mencocokkan dan excludemencocokkan segalanya kecuali apa yang ditentukan. Ini akan mengevaluasi ke dalam SQL sebagai NOT alias='' AND alias IS NOT NULL.

Tim Tisdall
sumber
Ini salah. Pertanyaan tersebut bertujuan untuk mengecualikan alias kosong ( alias="") dan NULL ( alias=None) dari kueri. Anda akan menyertakan contoh dengan Name(alias=None).
Damon
@damon - Saya menjawab apa yang setara .filter(alias!="")tapi bukan judulnya. Saya sudah mengedit jawaban saya. Namun, bidang karakter tidak boleh mengizinkan nilai NULL dan menggunakan string kosong untuk nilai yang tidak (sesuai dengan konvensi).
Tim Tisdall
-1

ini cara mudah lain untuk melakukannya.

Name.objects.exclude(alias=None)
ImadOS
sumber
Nonetidak sama dengan "".
Tim Tisdall