การกรองสำหรับชื่อว่างหรือ NULL ในชุดแบบสอบถาม


463

ฉันมีfirst_name, last_nameและalias(อุปกรณ์เสริม) ซึ่งผมต้องค้นหา ดังนั้นฉันต้องการแบบสอบถามเพื่อให้ชื่อทั้งหมดที่มีชื่อแทน

เฉพาะในกรณีที่ฉันสามารถทำได้:

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

ดังนั้นสิ่งที่เทียบเท่ากับข้างต้นคืออะไร?

คำตอบ:


839

คุณสามารถทำได้:

Name.objects.exclude(alias__isnull=True)

หากคุณต้องการยกเว้นค่า null และสตริงว่างวิธีที่ต้องการให้ทำคือเชื่อมโยงเงื่อนไขต่างๆดังนี้:

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

ผูกมัดวิธีการเหล่านี้ร่วมกันตรวจสอบโดยทั่วไปแต่ละสภาพเป็นอิสระในตัวอย่างข้างต้นเรายกเว้นแถวที่aliasเป็นทั้ง null หรือสตริงที่ว่างเปล่าเพื่อให้คุณได้รับทั้งหมดNameวัตถุที่มีไม่ว่างไม่ว่างaliasฟิลด์ SQL ที่สร้างขึ้นจะมีลักษณะดังนี้:

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

นอกจากนี้คุณยังสามารถส่งอาร์กิวเมนต์หลายรายการไปยังการโทรครั้งเดียวexcludeซึ่งจะช่วยให้มั่นใจว่าจะไม่รวมเฉพาะออบเจ็กต์ที่ตรงตามเงื่อนไขทุกข้อ :

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

ที่นี่แถวที่some_field และ other_fieldถูกรับจริงถูกแยกออกดังนั้นเราจึงได้แถวทั้งหมดที่ทั้งสองฟิลด์ไม่เป็นจริง รหัส SQL ที่สร้างขึ้นจะมีลักษณะเช่นนี้:

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

อีกทางหนึ่งถ้าตรรกะของคุณซับซ้อนกว่านั้นคุณสามารถใช้วัตถุ Qของ Django :

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

สำหรับข้อมูลเพิ่มเติมดูหน้านี้และหน้านี้ในเอกสาร Django

นอกเหนือจากนี้: ตัวอย่าง SQL ของฉันเป็นเพียงการเปรียบเทียบรหัส SQL ที่สร้างขึ้นจริงอาจมีลักษณะที่แตกต่างออกไป คุณจะได้รับความเข้าใจที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับการทำงานของแบบสอบถาม Django โดยการดู SQL ที่พวกเขาสร้างขึ้นจริง ๆ


5
ผมเชื่อว่าการแก้ไขของคุณไม่ถูกต้อง: ตีตรวนกรองไม่ได้โดยอัตโนมัติสร้าง SQL OR(เฉพาะในกรณีนี้) ก็ผลิต ANDSQL ดูหน้านี้สำหรับการอ้างอิง: docs.djangoproject.com/en/dev/topics/db/queries/…ข้อดีของการโยงคือคุณสามารถผสมexcludeและfilterสร้างแบบจำลองของเงื่อนไขการสืบค้นที่ซับซ้อน หากคุณต้องการจำลอง SQL จริงORคุณต้องใช้วัตถุ Django Q: docs.djangoproject.com/en/dev/topics/db/queries/?hl=th โปรดแก้ไขการแก้ไขของคุณเพื่อสะท้อนสิ่งนี้ .
shezi

1
@shezi: ฉันหมายถึงมันมากกว่าการเปรียบเทียบ - ฉันไม่ได้หมายความว่ารหัส SQL ที่แท้จริงรับประกันว่าจะใช้ORเงื่อนไขในการหลอมรวม ฉันจะแก้ไขคำตอบเพื่อชี้แจง
Sasha Chedygov

1
เก็บไว้ในใจว่ามีวิธีการที่แตกต่างกันเพื่อเป็นตัวแทนของตรรกะนี้ - เช่นเทียบเท่ากับNOT (A AND B) NOT A OR NOT Bฉันคิดว่ามันทำให้เกิดความสับสนกับนักพัฒนา Django ใหม่ที่รู้จัก SQL แต่ไม่คุ้นเคยกับ ORM
Sasha Chedygov

3
ฉันรู้ว่ากฎหมาย De ของมอร์แกนและนี่คือจุดของฉันว่า: ตัวอย่างของคุณทำงานได้เพียงเพราะมันจะได้ประโยชน์จากการเปิดANDในแบบสอบถามแรกเป็นเพราะคุณกำลังใช้OR excludeในกรณีทั่วไปก็อาจจะต้องมากขึ้นที่จะคิดว่าการผูกมัดเป็นเช่นTHEN exclude(A) THEN exclude(B)ขออภัยเกี่ยวกับภาษาที่รุนแรงข้างต้น คำตอบของคุณเป็นสิ่งที่ดีจริงๆ แต่ฉันกังวลเกี่ยวกับนักพัฒนาใหม่ที่รับคำตอบของคุณโดยทั่วไป
shezi

2
@shezi: ยุติธรรมเพียงพอ ฉันยอมรับว่ามันเป็นการดีกว่าที่จะคิดในแง่ของ Django และไม่ใช่ในแง่ SQL ฉันแค่คิดว่าการนำเสนอการผูกมัดในแง่ของANDและORอาจเป็นประโยชน์สำหรับคนที่มา Django จากพื้นหลัง SQL เพื่อความเข้าใจที่ลึกซึ้งยิ่งขึ้นของ Django ฉันคิดว่าเอกสารทำงานได้ดีกว่าที่ฉันสามารถทำได้
Sasha Chedygov

49
Name.objects.filter(alias__gt='',alias__isnull=False)

2
ฉันไม่แน่ใจ แต่ฉันคิดว่าalias__isnull=Falseเงื่อนไขซ้ำซ้อน หากสนามเป็นจริงNullมันจะถูกยกเว้นโดยประโยคแรก?
Bobble

นอกเหนือจากความเห็น / คำถามก่อนหน้านี้ฉันคิดว่าตรรกะในเชิงบวกที่นี่ง่ายต่อการติดตามมากกว่าคำตอบ
Bobble

@Bobble ที่จะขึ้นอยู่กับการใช้ฐานข้อมูล - การสั่งซื้อได้รับการมอบหมายไปยัง
wpercy

alias__gtเป็นสิ่งเดียวที่ทำงานสำหรับคอลัมน์ประเภท JSON ที่ผมอยากจะยกเว้นสตริงที่ว่างเปล่าจาก JSON {'something:''}เช่น ดังนั้นไวยากรณ์การทำงานคือ:jsoncolumnname__something__gt=''
bartgras

38

ประการแรกเอกสาร Django แนะนำอย่างยิ่งไม่แนะนำให้ใช้ค่า NULL สำหรับเขตข้อมูลแบบสตริงเช่น CharField หรือ TextField อ่านเอกสารประกอบสำหรับคำอธิบาย:

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

การแก้ไข: คุณสามารถเชื่อมโยงวิธีการต่างๆบน QuerySets ได้ด้วยฉันคิดว่า ลองสิ่งนี้:

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

นั่นควรให้ฉากที่คุณกำลังมองหา


5

จาก Django 1.8

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)

5
ดูเหมือนว่า "สิ่งที่คุณสามารถทำได้" ไม่ใช่สิ่งที่คุณควรทำ มันจะทำให้ความซับซ้อนของแบบสอบถามค่อนข้างซับซ้อนกว่าการตรวจสอบสองแบบ
Oli

3

เพื่อหลีกเลี่ยงข้อผิดพลาดทั่วไปเมื่อใช้excludeโปรดจำไว้ว่า:

คุณสามารถไม่ได้เพิ่มหลายเงื่อนไขเข้ายกเว้น ()filterบล็อกเช่น หากต้องการยกเว้นหลายเงื่อนไขคุณต้องใช้การยกเว้นหลายรายการ ()

ตัวอย่าง

ไม่ถูกต้อง :

User.objects.filter (email='example@example.com '). ยกเว้น (profile__nick_name =' ', profile__avt =' ')

ถูกต้อง :

User.objects.filter (email='example@example.com '). ยกเว้น (profile__nick_name =' '). ยกเว้น (profile__avt =' ')


0

คุณสามารถทำได้:

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

มันง่ายมาก ๆ filterใช้เพื่อจับคู่และexcludeเพื่อจับคู่ทุกอย่าง แต่สิ่งที่ระบุ นี้จะประเมินผลการศึกษาลงใน SQL NOT alias='' AND alias IS NOT NULLเป็น


สิ่งนี้ไม่ถูกต้อง คำถามนี้มีวัตถุประสงค์เพื่อแยกนามแฝงว่างเปล่า ( alias="") และ NULL ( alias=None) ออกจากแบบสอบถาม Name(alias=None)ขอแสดงจะรวมถึงกรณีที่มี
damon

@damon - ฉันกำลังตอบสิ่งที่เทียบเท่า.filter(alias!="")แต่ไม่ใช่ชื่อ ฉันแก้ไขคำตอบของฉันแล้ว อย่างไรก็ตามฟิลด์อักขระไม่ควรอนุญาตค่า NULL และใช้สตริงว่างสำหรับค่าที่ไม่ใช่ (ตามแบบแผน)
Tim Tisdall

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.