Django masuk / tidak dalam kueri


100

Saya mencoba mencari cara untuk menulis kueri gaya 'tidak dalam' di django. Misalnya, struktur kueri yang saya pikirkan akan terlihat seperti ini.

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

Seperti apa sintaks django yang mengasumsikan model disebut table1 dan table2?

Jawaban:


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

Fungsi pengecualian berfungsi seperti Notoperator yang Anda minta. Atribut flat = Truememberitahu table2query untuk mengembalikan value_listsebagai daftar satu tingkat. Jadi ... pada akhirnya Anda mendapatkan daftar IDsdari table2, yang akan Anda gunakan untuk menentukan kondisi di dalam table1, yang akan ditolak oleh fungsi pengecualian.


3
Saya juga mengalami masalah dengan konstruktor daftar [tabel2 ...] -> daftar (tabel2 ...) bekerja untuk saya.
RickyA

3
koreksi: table1.objects.exclude (id__in = table2.objects.filter (your_condition) .values_list ('id', flat = True))
Richard

1
Mencoba menggunakan solusi ini dan mengalami masalah, jadi jika terjadi pada orang lain ... Objs=Tbl1.objects.filter(...); IDs=Objs.values_list('id', flat=True); Objs.delete(); Tbl2.objects.filter(id__in=IDs')Ini tidak berhasil karena ID sebenarnya adalah objek QuerySet. Ketika saya menghapus baris asalnya, itu tidak lagi berfungsi dengan kueri lain. Solusinya adalah Tbl2.objects.filter(id__in=list(IDs))- mengubahnya menjadi daftar
Dakusan

1
Bergantung pada konteksnya, jika filter seperti "memiliki hitungan (xx) == yy", ini lebih dari 100x lebih cepat untuk digunakan annotate()(waktu itu memberi saya 1.0497902309998608 vs 0.00514069400014705)
Olivier Pons

10

dengan model ini:

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

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

Anda harus mendapatkan apa yang ingin Anda gunakan:

table1.objects.exclude(table2=some_param)

1
Ini masih membuat Anda berpotensi menarik BANYAK record dari db jika tidak perlu.
Jay Taylor

5
table1.objects.extra(where=["table1.id NOT IN (SELECT table2.key_to_table1 FROM table2 WHERE table2.id = some_parm)"])

1

Anda dapat menulis pencarian kustom untuk query Django:

Dari dokumentasi : "Mari kita mulai dengan kebiasaan lookup sederhana Kami akan menulis kustom lookup ne yang bekerja berlawanan dengan membalas . Author.objects.filter (name__ne = 'Jack') akan menerjemahkan ke 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)]]

Atau lebih baik

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
Mengulangi setiap baris dalam tabel. gg
Rebs
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.