Bagaimana saya melakukan yang tidak sama dalam penyaringan queryset Django?


666

Dalam model Django QuerySets, saya melihat bahwa ada __gtdan __ltuntuk nilai komparatif, tetapi apakah ada __ne/ !=/ <>( tidak sama dengan ?)

Saya ingin menyaring menggunakan yang tidak sama:

Contoh:

Model:
    bool a;
    int x;

saya ingin

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

The !=tidak sintaks yang benar. Aku mencoba __ne, <>.

Saya akhirnya menggunakan:

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

75
Apakah hasil = Model.objects.exclude (a = true) .filter (x = 5) telah berfungsi?
hughdbrown

3
@ hughdbrown. Tidak. Permintaan Anda mengecualikan semua a=trueterlebih dahulu dan kemudian menerapkan x=5filter pada sisanya. Permintaan yang dimaksud hanya membutuhkan yang dengan a=truedan x!=5. Perbedaannya adalah bahwa semua orang dengan a=truedan x=5juga disaring.
Mitchell van Zuylen

Jawaban:


690

Mungkin objek Q bisa membantu untuk masalah ini. Saya tidak pernah menggunakan mereka tetapi tampaknya mereka dapat dinegasikan dan dikombinasikan seperti ekspresi python normal.

Pembaruan: Saya Baru mencobanya, sepertinya berfungsi cukup baik:

>>> 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: lihat juga jawaban @ d4nt di bawah ini untuk sintaksis yang lebih intuitif.
Paul D. Waite

611

Kueri Anda tampaknya memiliki negatif ganda, Anda ingin mengecualikan semua baris di mana x tidak 5, jadi dengan kata lain Anda ingin memasukkan semua baris di mana x IS 5. Saya percaya ini akan melakukan trik.

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

Untuk menjawab pertanyaan spesifik Anda, tidak ada "tidak sama dengan" tetapi itu mungkin karena Django memiliki kedua metode "filter" dan "kecualikan" yang tersedia sehingga Anda selalu dapat dengan mudah mengubah putaran logika untuk mendapatkan hasil yang diinginkan.


2
@ d4nt: Saya mungkin salah, tapi saya pikir pertanyaannya seharusnyaresults = Model.objects.filter(a=true).exclude(x=5)
Taranjeet

1
@Taranjeet: Saya pikir Anda salah membaca kueri asli. Versi d4nt benar, karena OP ingin mengecualikan (a = Benar) dan meniadakan pengecualian x = 5 (yaitu termasuk itu).
Chuck

3
Saya pikir ini salah karena sebuah instance (x = 4, a = false) akan dikecualikan secara salah.
RemcoGerlich

4
@danigosa Sepertinya itu tidak benar. Saya hanya mencoba ini sendiri, dan urutan excludedan filterpanggilan tidak membuat perbedaan yang berarti. Urutan kondisi dalam WHEREklausa berubah, tetapi bagaimana masalahnya?
coredumperror

4
@danigosa urutan pengecualian dan filter tidak masalah.
EralpB

132

yang field=valuesintaks dalam permintaan adalah singkatan untuk field__exact=value. Artinya, Django menempatkan operator kueri di bidang kueri di pengidentifikasi . Django mendukung operator berikut:

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

Saya yakin dengan menggabungkan ini dengan objek Q seperti yang disarankan Dave Vogt dan menggunakan filter()atau exclude()seperti yang disarankan Jason Baker, Anda akan mendapatkan apa yang Anda butuhkan untuk pertanyaan apa pun yang mungkin.


terima kasih ini luar biasa. Saya menggunakan beberapa hal seperti ini tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$')dan itu berfungsi.
suhailvs

@suhail, harap diingat bahwa tidak semua database mendukung sintaks regex :)
Anoyz

2
i in icontains, iexactdan singkatan yang sama untuk "abaikan sensitivitas huruf". Ini bukan untuk "terbalik".
Ivy Growing

Perlu dicatat bahwa ketika Anda menggunakan exclude()dengan beberapa istilah, Anda mungkin ingin membuat proposisi dengan ORoperator, misalnya exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2))untuk mengecualikan hasil dalam kedua kondisi.
clapas

98

Sangat mudah untuk membuat pencarian kustom dengan Django 1.7. Ada __necontoh pencarian dalam dokumentasi resmi Django .

Anda harus membuat pencarian itu sendiri terlebih dahulu:

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

Maka Anda perlu mendaftarkannya:

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

Dan sekarang Anda dapat menggunakan __nepencarian di pertanyaan Anda seperti ini:

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

88

Di Django 1.9 / 1.10 ada tiga opsi.

  1. Rantai excludedanfilter

    results = Model.objects.exclude(a=true).filter(x=5)
  2. Gunakan Q()benda dan ~operator

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
    
  3. Daftarkan fungsi pencarian kustom

    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
    

    The register_lookupdekorator ditambahkan pada Django 1,8 dan memungkinkan kustom lookup seperti biasa:

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

1
object_list = QuerySet.filter (~ Q (a = True), x = 5): Ingatlah untuk menjaga semua kondisi lainnya tidak mengandung Q setelah yang mengandung Q.
Bhumi Singhal

1
@MichaelHoffmann: A) Anda kemudian akan memfilter pada set data yang lebih kecil setelah pengecualian menggunakan ~ Q jadi lebih efisien. B) mungkin urutan sebaliknya tidak berfungsi .. tidak tahu .. tidak ingat!
Bhumi Singhal

41

Sementara dengan Model, Anda dapat menyaring dengan =, __gt, __gte, __lt, __lte, Anda tidak dapat menggunakan ne, !=atau <>. Namun, Anda dapat mencapai pemfilteran yang lebih baik dalam menggunakan objek Q.

Anda dapat menghindari rantai QuerySet.filter()dan QuerySet.exlude(), dan gunakan ini:

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

24

Keputusan desain yang tertunda. Sementara itu, gunakanexclude()

Pelacak masalah Django memiliki entri luar biasa # 5763 , berjudul "Queryset tidak memiliki operator filter" tidak sama "" . Ini luar biasa karena (per April 2016) "dibuka 9 tahun yang lalu" (di zaman batu Django), "ditutup 4 tahun lalu", dan "terakhir diubah 5 bulan yang lalu".

Bacalah diskusi, itu menarik. Pada dasarnya, beberapa orang berdebat __neharus ditambahkan sementara yang lain mengatakan exclude()lebih jelas dan karenanya __ne harus tidak ditambahkan.

(Saya setuju dengan yang pertama, karena argumen terakhir kira-kira sama dengan mengatakan Python seharusnya tidak ada !=karena sudah ==dan notsudah ...)


22

Menggunakan kecualikan dan filter

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

18

Anda harus menggunakan filterdan excludemenyukai ini

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

8

Bit kode terakhir akan mengecualikan semua objek di mana x! = 5 dan a adalah Benar. Coba ini:

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

Ingat, tanda = pada baris di atas memberikan False ke parameter a dan angka 5 ke parameter x. Itu tidak memeriksa kesetaraan. Jadi, sebenarnya tidak ada cara untuk menggunakan simbol! = Dalam panggilan kueri.


3
Itu bukan 100% hal yang sama karena mungkin juga ada nilai Null untuk bidang tersebut.
MikeN

Ini mengembalikan hanya item-item yang memiliki = Salah dan x = 5, tetapi dalam pertanyaan contoh (a = salah, x = 4) akan dimasukkan.
RemcoGerlich

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

8

hasil = Model.objects.filter (a = Benar) .exclude (x = 5)
Hasilkan sql ini:
pilih * dari tablex di mana a = = dan x! = 5
Sql tergantung pada bagaimana bidang Benar / Salah Anda diwakili, dan mesin basis data. Kode Django adalah semua yang Anda butuhkan.



6

Apa yang Anda cari adalah semua objek yang memiliki a=false atau x=5 . Di Django, |berfungsi sebagai ORoperator antara kueri:

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

5

Ini akan memberikan hasil yang Anda inginkan.

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

karena tidak sama Anda dapat menggunakan ~kueri yang sama. jelas, Qdapat digunakan untuk mencapai kueri yang sama.


Silakan periksa hasil edit; menggunakan "dan" dalam Q(a=True) and ~Q(x=5)akan mengevaluasi ~Q(x=5)sebagai argumen untuk .exclude. Silakan baca: docs.python.org/3/reference/expressions.html#boolean-operations dan docs.python.org/3/reference/… .
tzot

2

Waspadai banyak jawaban yang salah untuk pertanyaan ini!

Logika Gerard benar, meskipun itu akan mengembalikan daftar daripada queryset (yang mungkin tidak masalah).

Jika Anda membutuhkan queryset, gunakan Q:

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.