วิธีการหรือเงื่อนไขในชุดแบบสอบถาม django?


294

ฉันต้องการเขียนแบบสอบถาม Django ที่เทียบเท่ากับแบบสอบถาม SQL นี้:

SELECT * from user where income >= 5000 or income is NULL.

วิธีสร้างตัวกรองชุดการสืบค้น Django

User.objects.filter(income__gte=5000, income=0)

สิ่งนี้ไม่ทำงานเพราะมันANDเป็นตัวกรอง ฉันต้องการORตัวกรองเพื่อรับชุดแบบสอบถามแต่ละชุด


คำตอบ:


548
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

ผ่านเอกสาร


มันจะช่วยถ้าคุณเพิ่มการพิมพ์ของ object.query เพื่อให้เราสามารถเชื่อมโยงทั้งเอาต์พุต ORM และ Query เพื่อทำความคุ้นเคยกับมัน ตัวอย่างที่ดีของ BTW
Eddwin Paz

มันจะดีกว่าถ้าใช้แบบสอบถามชนิดนี้หรือทำแบบสอบถามที่แยกต่างหากสอง
MHB

60

เนื่องจากQuerySets ใช้ตัวดำเนินการ Python __or__( |) หรือ union มันจึงใช้งานได้ ในขณะที่คุณคาดหวังที่|ผู้ประกอบการไบนารีส่งกลับQuerySetเพื่อให้order_by(), .distinct()และฟิลเตอร์ queryset อื่น ๆ สามารถติดอยู่ไปยังจุดสิ้นสุด

combined_queryset = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)
ordered_queryset = combined_queryset.order_by('-income')

ปรับปรุง 2019/06/20: นี่คือตอนนี้เอกสารครบถ้วนในDjango 2.1 ชุดข้อความอ้างอิง การอภิปรายทางประวัติศาสตร์อื่น ๆ สามารถพบได้ในDjangoProject ตั๋ว #


18
"ไม่มีเอกสาร" และ "มรดก" ทำให้ฉันกลัว ฉันคิดว่ามันปลอดภัยกว่าที่จะใช้วัตถุ Q ดังรายละเอียดในคำตอบที่ยอมรับได้ที่นี่
0atman

2
ปีงบประมาณ, order_by () และชัดเจน () สามารถนำไปใช้กับชุด
แบบสอบถาม piped

@carruthd ขอบคุณ ฉันยืนยันเรื่องนี้เช่นกัน จะแก้ไข
hobs

order_by () สามารถนำไปใช้กับแต่ละชุดแบบสอบถามแล้วรวมกันได้หรือไม่ เพื่อให้คำสั่งสำหรับแต่ละเงื่อนไขยังคงอยู่? ตัวอย่างเช่น combination_queryset = User.objects.filter (Income__gte = 5000) .order_by ('รายได้') | User.objects.filter (earn__lt = 5,000) .order_by ('- รายได้')?
หยุดชะงัก

2
@Oatman: | เอกสารประกอบการ ดูdocs.djangoproject.com/en/2.0/ref/models/querysets : "โดยทั่วไปแล้ววัตถุ Q () ทำให้สามารถกำหนดและนำเงื่อนไขกลับมาใช้ใหม่ได้ซึ่งจะอนุญาตให้สร้างคิวรีฐานข้อมูลที่ซับซ้อนโดยใช้ | (OR) และ & ( ตัวดำเนินการ AND) โดยเฉพาะอย่างยิ่งไม่สามารถใช้ OR ใน QuerySets ได้ ฉันไม่ได้ตรวจสอบเอกสารสำหรับรุ่นก่อนหน้า แต่ผู้ปฏิบัติงานไปป์ทำงานจาก Django 1.1.4 เป็นอย่างน้อย
makeroo

10

ตัวเลือกทั้งสองถูกกล่าวถึงแล้วในคำตอบที่มีอยู่:

from django.db.models import Q
q1 = User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

และ

q2 = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)

อย่างไรก็ตามดูเหมือนว่าจะมีความสับสนเกี่ยวกับการที่จะชอบ

ประเด็นคือพวกเขาเหมือนกันในระดับ SQLดังนั้นอย่าลังเลที่จะเลือกว่าคุณชอบแบบไหน!

Django ออมตำราพูดในรายละเอียดบางเกี่ยวกับเรื่องนี้ที่นี่เป็นส่วนหนึ่งที่เกี่ยวข้อง:


queryset = User.objects.filter(
        first_name__startswith='R'
    ) | User.objects.filter(
    last_name__startswith='D'
)

นำไปสู่

In [5]: str(queryset.query)
Out[5]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
"auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
"auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
"auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

และ

qs = User.objects.filter(Q(first_name__startswith='R') | Q(last_name__startswith='D'))

นำไปสู่

In [9]: str(qs.query)
Out[9]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
 "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
  "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
  "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
  WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

แหล่งที่มา: django-orm-cookbook


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