Django ใน / ไม่อยู่ในแบบสอบถาม


105

ฉันกำลังพยายามหาวิธีเขียนแบบสอบถามสไตล์ 'not in' ใน django ตัวอย่างเช่นโครงสร้างแบบสอบถามที่ฉันคิดจะมีลักษณะเช่นนี้

select table1.* 
from table1
where table1.id not in 
(
  select table2.key_to_table1
  from table2 
  where table2.id = some_parm 
)

ไวยากรณ์ของ django จะเป็นอย่างไรโดยสมมติว่าโมเดลที่เรียกว่า table1 และ table2

คำตอบ:


169
table1.objects.exclude(id__in=
    table2.objects.filter(your_condition).values_list('id', flat=True))

ฟังก์ชันการยกเว้นจะทำงานเหมือนกับตัวNotดำเนินการที่คุณขอ แอตทริบิวต์flat = Trueบอกให้table2แบบสอบถามส่งคืนvalue_listเป็นรายการระดับเดียว ในตอนท้ายคุณจะได้รับรายชื่อIDsจาก table2 ซึ่งคุณกำลังจะให้ผู้ใช้กำหนดเงื่อนไขtable1ซึ่งจะถูกปฏิเสธโดยฟังก์ชันยกเว้น


3
ฉันยังมีปัญหากับตัวสร้างรายการ [table2 ... ] -> รายการ (table2 ... ) ใช้งานได้สำหรับฉัน
RickyA

3
แก้ไข: table1.objects.exclude (id__in = table2.objects.filter (your_condition) .values_list ('id', flat = True))
Richard

1
กำลังพยายามใช้โซลูชันนี้และประสบปัญหาดังนั้นหากเกิดขึ้นกับคนอื่น ... Objs=Tbl1.objects.filter(...); IDs=Objs.values_list('id', flat=True); Objs.delete(); Tbl2.objects.filter(id__in=IDs')สิ่งนี้ใช้ไม่ได้เพราะ ID เป็นวัตถุ QuerySet เมื่อฉันลบแถวที่เกิดขึ้นมันจะไม่ทำงานกับการสืบค้นอื่น ๆ อีกต่อไป วิธีแก้ปัญหาคือTbl2.objects.filter(id__in=list(IDs))- เปลี่ยนเป็นรายการ
Dakusan

1
ขึ้นอยู่กับบริบทถ้าตัวกรองเป็นแบบ "มีจำนวน (xx) == yy" ใช้งานได้เร็วกว่า 100 เท่าannotate()(เวลาให้ฉัน 1.0497902309998608 เทียบกับ 0.00514069400014705)
Olivier Pons

11

ด้วยโมเดลเหล่านี้:

class table1(models.Model):
    field1 = models.CharField(max_length=10)      # a dummy field

class table2(models.Model):
    key_to_table1 = models.ForeignKey(table1)

คุณควรได้รับสิ่งที่คุณต้องการโดยใช้:

table1.objects.exclude(table2=some_param)

1
สิ่งนี้ยังคงทำให้คุณดึงบันทึกจำนวนมากจากฐานข้อมูลโดยไม่จำเป็น
Jay Taylor


1

คุณสามารถเขียนการค้นหาแบบกำหนดเองสำหรับแบบสอบถาม Django:

จากเอกสาร : "เริ่มต้น Let 's ด้วยการค้นหาที่กำหนดเองง่าย ๆ เราจะเขียนการค้นหาที่กำหนดเองภาคตะวันออกเฉียงเหนือที่ทำงานตรงข้ามกับที่แน่นอน . Author.objects.filter (name__ne = 'แจ็ค')จะแปล SQL: "author"."name" <> 'Jack'"

from django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

    def as_sql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return '%s <> %s' % (lhs, rhs), params

-16
[o1 for o1 in table1.objects.all() if o1.id not in [o2.id for o2 in table2.objects.filter(id=some_parm)]]

หรือดีกว่า

not_in_ids = [obj.id for obj in table2.objects.filter(id=some_parm)]
selected_objects = [obj for obj in table1.objects.iterator() if obj.id not in not_in_ids]

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