ฉันจะทำไม่เท่ากันในการกรองชุดการสืบค้น Django ได้อย่างไร


664

ใน Django model QuerySets ฉันเห็นว่ามี__gtและ__ltสำหรับค่าเปรียบเทียบ แต่มี a __ne/ !=/ <>( ไม่เท่ากับ ?)

ฉันต้องการที่จะกรองโดยใช้ไม่เท่ากับ:

ตัวอย่าง:

Model:
    bool a;
    int x;

ฉันต้องการ

results = Model.objects.exclude(a=true, x!=5)

!=ไม่ไวยากรณ์ที่ถูกต้อง ฉันพยายาม__neแล้ว, <>.

ฉันสิ้นสุดการใช้:

results = Model.objects.exclude(a=true, x__lt=5).exclude(a=true, x__gt=5)

75
ผลลัพธ์ = Model.objects.exclude (a = true) .filter (x = 5) ทำงานได้หรือไม่
hughdbrown

3
@hughdbrown ไม่แบบสอบถามของคุณไม่รวมทั้งหมดa=trueก่อนแล้วจึงใช้x=5ตัวกรองที่เหลือ แบบสอบถามตั้งใจที่จำเป็นเฉพาะผู้ที่มีและa=true x!=5ความแตกต่างที่ถูกว่าสิ่งเหล่านั้นด้วยa=trueและx=5จะถูกกรองยังออก
Mitchell van Zuylen

คำตอบ:


690

บางทีวัตถุ Qอาจช่วยในปัญหานี้ได้ ฉันไม่เคยใช้มัน แต่ดูเหมือนว่าพวกมันจะถูกทำให้เป็นโมฆะและรวมเข้าด้วยกันเหมือนกับการแสดงออกของไพ ธ อน

อัปเดต: ฉันเพิ่งลองใช้ดูเหมือนว่าจะทำงานได้ดี:

>>> from myapp.models import Entry
>>> from django.db.models import Q

>>> Entry.objects.filter(~Q(id = 3))

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]

16
@ JCLeitão: ดูเพิ่มเติมที่คำตอบของ @ d4nt ด้านล่างสำหรับไวยากรณ์ที่ใช้งานง่ายขึ้น
Paul D. Waite

610

ข้อความค้นหาของคุณดูเหมือนจะมีค่าลบเป็นสองเท่าคุณต้องการยกเว้นแถวทั้งหมดที่ x ไม่เท่ากับ 5 ดังนั้นในคำอื่น ๆ ที่คุณต้องการรวมแถวทั้งหมดที่ x IS 5 ฉันเชื่อว่านี่จะเป็นการหลอกลวง

results = Model.objects.filter(x=5).exclude(a=true)

เพื่อตอบคำถามเฉพาะของคุณไม่มี "ไม่เท่ากับ" แต่อาจเป็นเพราะ django มีทั้ง "ตัวกรอง" และ "แยก" วิธีการที่มีอยู่เพื่อให้คุณสามารถสลับตรรกะรอบเพื่อให้ได้ผลลัพธ์ที่ต้องการ


2
@ d4nt: ฉันอาจจะผิด แต่ฉันคิดว่าแบบสอบถามควรจะเป็นresults = Model.objects.filter(a=true).exclude(x=5)
Taranjeet

1
@Taranjeet: ฉันคิดว่าคุณอ่านข้อความต้นฉบับผิด เวอร์ชันของ d4nt นั้นถูกต้องเนื่องจาก OP ต้องการยกเว้น (a = True) และปฏิเสธการยกเว้นของ x = 5 (เช่นรวมไว้ด้วย)
Chuck

3
ฉันคิดว่านี่เป็นสิ่งที่ผิดเพราะอินสแตนซ์ (x = 4, a = false) จะถูกยกเว้นอย่างผิด ๆ
RemcoGerlich

4
@danigosa ดูเหมือนไม่ถูกต้อง ฉันแค่ลองเองและคำสั่งexcludeและการfilterโทรไม่ได้สร้างความแตกต่างที่มีความหมาย ลำดับของเงื่อนไขในWHEREข้อเปลี่ยนแปลง แต่สิ่งนั้นสำคัญอย่างไร
coredumperror

4
@danigosa คำสั่งยกเว้นและตัวกรองไม่สำคัญ
EralpB

132

ไวยากรณ์ในการสืบค้นเป็นชวเลขเป็นfield=value field__exact=valueนั่นคือจะบอกว่าผู้ประกอบการ Django ทำให้แบบสอบถามในเขตข้อมูลแบบสอบถามในตัวระบุ Django รองรับผู้ให้บริการดังต่อไปนี้:

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range
year
month
day
week_day
isnull
search
regex
iregex

ฉันแน่ใจว่าด้วยการรวมสิ่งเหล่านี้กับวัตถุ Q ตามที่Dave Vogt แนะนำและใช้filter()หรือexclude()เป็นJason Baker แนะนำว่าคุณจะได้สิ่งที่คุณต้องการสำหรับการสืบค้นที่เป็นไปได้ทั้งหมด


ขอบคุณมันยอดเยี่ยม ฉันใช้สิ่งนี้tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$')และใช้งานได้
suhailvs

@suhail โปรดทราบว่าไม่สนับสนุนฐานข้อมูลทั้งหมดที่ regex ไวยากรณ์ :)
Anoyz

2
ฉันในicontains, iexactและยืนที่คล้ายกันสำหรับ "ละเว้นความไวกรณี" มันไม่ได้สำหรับ "ตรงกันข้าม"
Ivy Growing

เป็นที่น่าสังเกตว่าเมื่อคุณใช้exclude()กับเงื่อนไขหลายข้อคุณอาจต้องการเขียนข้อเสนอกับORผู้ประกอบการเช่นexclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2))เพื่อแยกผลลัพธ์ภายใต้เงื่อนไขทั้งสอง
clapas

98

ง่ายในการสร้างการค้นหาที่กำหนดเองด้วย Django 1.7 มีเป็น__neตัวอย่างการค้นหาในเอกสารที่เป็นทางการ Django

คุณต้องสร้างการค้นหาเองก่อน:

from django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

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

จากนั้นคุณต้องลงทะเบียน:

from django.db.models.fields import Field
Field.register_lookup(NotEqual)

และตอนนี้คุณสามารถใช้การ__neค้นหาในข้อความค้นหาของคุณเช่นนี้:

results = Model.objects.exclude(a=True, x__ne=5)

88

ในDjango 1.9 / 1.10มีสามตัวเลือก

  1. เครือข่ายexcludeและfilter

    results = Model.objects.exclude(a=true).filter(x=5)
  2. ใช้Q()วัตถุและ~ผู้ประกอบการ

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
  3. ลงทะเบียนฟังก์ชั่นการค้นหาที่กำหนดเอง

    from django.db.models import Lookup
    from django.db.models.fields import Field
    
    @Field.register_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

    register_lookupมัณฑนากรที่ถูกเพิ่มเข้ามาในDjango 1.8และช่วยกำหนดเองค้นหาตามปกติ:

    results = Model.objects.exclude(a=True, x__ne=5)

1
object_list = QuerySet.filter (~ Q (a = True), x = 5): อย่าลืมรักษาเงื่อนไขอื่น ๆ ทั้งหมดที่ไม่มี Q หลังจากผู้ที่มีคำถาม Q.
Bhumi Singhal

1
@MichaelHoffmann: A) จากนั้นคุณจะกรองชุดข้อมูลขนาดเล็กลงหลังจากการยกเว้นโดยใช้ ~ Q ดังนั้นจึงมีประสิทธิภาพมากขึ้น B) อาจเป็นไปได้ว่าการเรียงลำดับวิธีอื่น ๆ ไม่ได้ผล .. dun รู้ .. dun จำได้!
Bhumi Singhal

41

ในขณะที่รุ่นที่คุณสามารถกรองด้วย=, __gt, __gte, __lt, __lteคุณจะไม่สามารถใช้ne, หรือ!= <>อย่างไรก็ตามคุณสามารถบรรลุการกรองที่ดีขึ้นเกี่ยวกับการใช้วัตถุ Q

คุณสามารถหลีกเลี่ยงการผูกมัดQuerySet.filter()และQuerySet.exlude()และใช้สิ่งนี้:

from django.db.models import Q
object_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')

24

รอการตัดสินใจออกแบบ ในขณะเดียวกันใช้exclude()

Django มีปัญหาติดตามมีที่โดดเด่นรายการ # 5763หัวข้อ"ชุดข้อความไม่ได้ 'ไม่เท่ากับ' กรองผู้ประกอบการ" มันน่าทึ่งเพราะ (ณ เดือนเมษายน 2559) มันเป็น "เปิดเมื่อ 9 ปีก่อน" (ในยุคหิน Django) "ปิดเมื่อ 4 ปีก่อน" และ "เปลี่ยนไปเมื่อ 5 เดือนที่ผ่านมา"

อ่านผ่านการสนทนาเป็นที่น่าสนใจ โดยพื้นฐานแล้วบางคนโต้แย้ง__neควรเพิ่มในขณะที่คนอื่นพูดว่าexclude()ชัดเจนและดังนั้นจึงไม่__ne ควรเพิ่ม

(ผมเห็นด้วยกับอดีตเพราะอาร์กิวเมนต์หลังเป็นเทียบเท่าประมาณที่จะบอกว่างูใหญ่ไม่ควรมี!=เพราะมันมี==และnotแล้ว ... )




8

รหัสสุดท้ายจะแยกวัตถุทั้งหมดที่ x! = 5 และ a เป็นจริง ลองสิ่งนี้:

results = Model.objects.filter(a=False, x=5)

จำไว้ว่าเครื่องหมาย = ในบรรทัดด้านบนกำลังกำหนดค่าเท็จให้กับพารามิเตอร์ a และตัวเลข 5 ให้กับพารามิเตอร์ x มันไม่ได้ตรวจสอบความเท่าเทียมกัน ดังนั้นจึงไม่มีวิธีใช้สัญลักษณ์! = ในการเรียกใช้แบบสอบถาม


3
นั่นไม่ใช่สิ่งเดียวกัน 100% เนื่องจากอาจมีค่า Null สำหรับฟิลด์เหล่านั้น
MikeN

สิ่งนี้จะส่งกลับเฉพาะไอเท็มที่มี = False และ x = 5 แต่ในคำถามจะมีอินสแตนซ์ (a = false, x = 4)
RemcoGerlich

1
results = Model.objects.filter(a__in=[False,None],x=5)
Jeremy

8

ผลลัพธ์ = Model.objects.filter (a = True) .exclude (x = 5)
สร้าง sql นี้:
เลือก * จาก tablex โดยที่ a = 0 และ x! = 5
sql ขึ้นอยู่กับการแสดงฟิลด์ True / False ของคุณและเอ็นจิ้นฐานข้อมูล รหัส django นั้นเป็นสิ่งที่คุณต้องการ


8

Django-model-values (การเปิดเผยข้อมูล: ผู้เขียน) จัดทำการใช้งานการค้นหาNotEqualเช่นเดียวกับคำตอบนี้ นอกจากนี้ยังให้การสนับสนุนวากยสัมพันธ์สำหรับมัน:

from model_values import F
Model.objects.exclude(F.x != 5, a=True)

6

สิ่งที่คุณกำลังมองหาวัตถุทั้งหมดที่มีอย่างใดอย่างหนึ่งหรือa=false x=5ใน Django |ทำหน้าที่เป็นORโอเปอเรเตอร์ระหว่างชุดการสืบค้น:

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)

5

สิ่งนี้จะให้ผลลัพธ์ที่คุณต้องการ

from django.db.models import Q
results = Model.objects.exclude(Q(a=True) & ~Q(x=5))

เพราะไม่เท่ากันคุณสามารถใช้~กับแบบสอบถามที่เท่ากัน เห็นได้ชัดว่าQสามารถใช้เพื่อเข้าถึงแบบสอบถามที่เท่ากัน


โปรดตรวจสอบการแก้ไข; โดยใช้“และ” ในQ(a=True) and ~Q(x=5)จะประเมินเพื่อเป็นข้อโต้แย้งที่จะ~Q(x=5) .excludeโปรดอ่าน: docs.python.org/3/reference/expressions.html#boolean-operationsและdocs.python.org/3/reference/...
tzot

2

ระวังคำตอบที่ไม่ถูกต้องสำหรับคำถามนี้!

ตรรกะของเจอราร์ดนั้นถูกต้องแม้ว่ามันจะส่งคืนรายการแทนที่จะเป็นชุดคำถาม (ซึ่งอาจไม่สำคัญ)

หากคุณต้องการชุดแบบสอบถามให้ใช้ Q:

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.