ตรวจสอบชุดสืบค้นว่างใน Django


183

สำนวนที่แนะนำสำหรับการตรวจสอบว่าแบบสอบถามส่งกลับผลลัพธ์ใด ๆ ?
ตัวอย่าง:

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

ฉันคิดว่ามีหลายวิธีในการตรวจสอบสิ่งนี้ แต่ฉันต้องการทราบว่าผู้ใช้ Django ที่มีประสบการณ์จะทำเช่นไร ตัวอย่างส่วนใหญ่ในเอกสารเพิ่งเพิกเฉยกรณีที่ไม่พบสิ่งใด ...

คำตอบ:


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

5
ดูเหมือนว่าจะเป็นที่ต้องการในเอกสารเช่นกัน: docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7
Wtower

1
@Wtower รหัสที่คุณอ้างถึงมีไว้สำหรับสัญญาที่จะเพิ่ม 404 ถ้านิพจน์การกรองไม่กระทบระเบียนใด ๆ หรือสร้างlistผลลัพธ์หากมีระเบียน รหัสที่นั่นจะตีฐานข้อมูลเพียงครั้งเดียว หากพวกเขาใช้exist()หรือcount()เพื่อตรวจสอบก่อนว่าจะมีการส่งคืนระเบียนพวกเขาจะกดฐานข้อมูลสองครั้ง (หนึ่งครั้งเพื่อตรวจสอบหนึ่งครั้งเพื่อรับบันทึก) นี่เป็นสถานการณ์ที่เฉพาะเจาะจง มันไม่ได้นำมาซึ่งในกรณีทั่วไปวิธีการที่ต้องการรู้ว่าแบบสอบถามจะส่งกลับระเบียนที่จะใช้ทำif queryset:...
Louis

1
@Louis รหัสที่ฉันอ้างถึงเป็นเพียงตัวอย่างที่มีบรรทัดif not my_objects:เพื่อแสดงให้เห็นว่านี่เป็นวิธีที่พวกเขาทำในเอกสาร ทุกอย่างอื่นไม่เกี่ยวข้องอย่างเต็มที่ดังนั้นฉันไม่ได้รับคะแนนของคุณ พวกเขาสามารถทำข้อซักถามนับพันข้อและยังคงไม่เกี่ยวข้องโดยสิ้นเชิงเนื่องจากนี่ไม่ใช่ประเด็นของคำตอบนี้ซึ่งฉันชัดเจนว่าฉันเห็นด้วย
Wtower

1
@ Power นั่นเป็นเพียงคำอธิบายวิธีการget_object_or_404ทำงานไม่ใช่วิธีที่ต้องการในการตรวจสอบว่ามีองค์ประกอบใด ๆ ในชุดแบบสอบถามหรือไม่ การทำรายการ () ในชุดแบบสอบถามจะดึงข้อมูลทุกวัตถุในชุดแบบสอบถามซึ่งจะแย่กว่าการสืบค้นสองครั้งหากมีการส่งคืนแถวจำนวนมาก
minmaxavg

1
สำหรับคำตอบโดยละเอียดเพิ่มเติมดูที่คำตอบของ @ leonid-shvechikov ด้านล่าง: การใช้.exists()มีประสิทธิภาพมากขึ้นถ้า qs จะไม่ถูกประเมิน
guival

191

ตั้งแต่เวอร์ชัน 1.2 เป็นต้นมา Django มี QuerySet มีอยู่ ()วิธีการซึ่งมีประสิทธิภาพมากที่สุด:

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

แต่ถ้าคุณจะประเมิน QuerySet ล่ะก็ควรใช้:

if orgs:
   ...

สำหรับข้อมูลเพิ่มเติมอ่าน QuerySet.exists () เอกสาร


.exists () มีไว้สำหรับ. filter () มีบางอย่างสำหรับ. get () หรือไม่
หมุน

.getไม่ส่งคืนชุดแบบสอบถาม ส่งคืนวัตถุ ดังนั้น google สำหรับที่
Aseem

จะมีประสิทธิภาพมากขึ้นอย่างเห็นได้ชัดหากคุณมี QuerySet ขนาดใหญ่: docs.djangoproject.com/en/2.1/ref/models/querysets/#exists
Nathan Jones

16

หากคุณมีวัตถุจำนวนมากสิ่งนี้สามารถทำได้เร็วขึ้น:

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

ในโครงการที่ฉันทำงานด้วยฐานข้อมูลขนาดใหญ่not orgsคือ 400+ มิลลิวินาทีและorgs.count()250 มิลลิวินาที ในกรณีการใช้งานทั่วไปของฉัน (ผู้ที่มีผลลัพธ์) เทคนิคนี้มักจะลดลงต่ำกว่า 20ms (กรณีหนึ่งที่ฉันพบมันคือ 6)

แน่นอนว่าอาจนานกว่านั้นมากขึ้นอยู่กับว่าฐานข้อมูลต้องค้นหาผลลัพธ์อย่างไร หรือเร็วกว่านั้นหากพบเจออย่างรวดเร็ว YMMV

แก้ไข: นี้จะมักจะช้ากว่าที่orgs.count()ถ้าผลที่ได้คือไม่พบโดยเฉพาะอย่างยิ่งถ้าเงื่อนไขที่คุณกรองเป็นที่หายากหนึ่ง ด้วยเหตุนี้จึงมีประโยชน์อย่างยิ่งในฟังก์ชั่นมุมมองที่คุณต้องแน่ใจว่ามุมมองนั้นมีอยู่หรือโยน Http404 (ที่หนึ่งหวังว่าผู้คนกำลังถามหา URL ที่มีอยู่บ่อยกว่า)


10

วิธีตรวจสอบความว่างเปล่าของชุดแบบสอบถาม:

if orgs.exists():
    # Do something

หรือคุณสามารถตรวจสอบรายการแรกในชุดแบบสอบถามหากไม่มีอยู่มันจะส่งคืนNone:

if orgs.first():
    # Do something

7
if orgs.exists()ถูกครอบคลุมโดยคำตอบที่ให้ไว้ประมาณ 5 ปีก่อนหน้านี้ สิ่งเดียวที่คำตอบนี้นำมาสู่ตารางซึ่งเป็นอาจจะif orgs.first()เป็นของใหม่ (แม้จะเป็นที่ถกเถียงกัน: มันแตกต่างอย่างมากจากการทำorgs[0] ข้อเสนอแนะเมื่อประมาณ 5 ปีที่แล้วด้วยหรือไม่) คุณควรพัฒนาส่วนหนึ่งของคำตอบ: เมื่อใดที่คุณต้องการทำสิ่งนี้แทนการแก้ปัญหาอื่น ๆ
หลุยส์

9

วิธีที่มีประสิทธิภาพที่สุด (ก่อน django 1.2) คือ:

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

5
.exists () ดูเหมือนว่าจะมีประสิทธิภาพยิ่งขึ้น
dzida

5
ยกเว้นว่ามีอยู่. () ถูกเพิ่มเข้าไปไม่กี่เดือนหลังจากความคิดเห็นของฉันและ Django 1.2 (ซึ่งรวมนิติบุคคลนั้น) ได้รับการเผยแพร่ ~ 8 เดือนต่อมา แต่ขอขอบคุณสำหรับการลงคะแนนเสียงและไม่รบกวนการตรวจสอบข้อเท็จจริง
Bartosz

4
ขออภัยฉันได้เพิ่มการแก้ไขเล็กน้อยในคำตอบของคุณเพื่อให้แม่นยำยิ่งขึ้นและลงคะแนนในเชิงบวก
dzida

4

ฉันไม่เห็นด้วยกับคำกริยา

if not orgs:

มันควรจะเป็น

if not orgs.count():

ฉันมีปัญหาเดียวกันกับชุดผลลัพธ์ที่ค่อนข้างใหญ่ (ผลลัพธ์ประมาณ ~ 150k) ตัวดำเนินการไม่ได้บรรทุกมากเกินไปใน QuerySet ดังนั้นผลลัพธ์จะแตกออกเป็นรายการก่อนที่จะทำการตรวจสอบ ในกรณีของฉันเวลาดำเนินการลงไปสามคำสั่ง


6
__nonzero__ มีการโหลดมากเกินไปใน QuerySet แล้ว ถ้าผลลัพธ์นั้นไม่ถูกแคช (มันไม่เคยถูกใช้งานครั้งแรกของชุดการสืบค้น) พฤติกรรมของ __nonzero__ คือการวนซ้ำองค์ประกอบทั้งหมดในชุดการสืบค้น มันแย่มากถ้าชุดใหญ่
hedleyroos

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