Django in / non in query


100

Sto cercando di capire come scrivere una query in stile "non in" in django. Ad esempio, la struttura della query a cui sto pensando sarebbe simile a questa.

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

Come sarebbe la sintassi di django assumendo modelli chiamati table1 e table2?

Risposte:


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

La funzione di esclusione funziona come l' Notoperatore che stai chiedendo. L'attributo flat = Trueindica alla table2query di restituire value_listun elenco a un livello. Quindi ... alla fine stai ottenendo un elenco di IDsda table2, in cui stai per definire la condizione table1, che sarà negata dalla funzione di esclusione.


3
Ho anche avuto problemi con il costruttore della lista [table2 ...] -> list (table2 ...) ha funzionato per me.
RickyA

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

1
Stavo cercando di utilizzare questa soluzione e Objs=Tbl1.objects.filter(...); IDs=Objs.values_list('id', flat=True); Objs.delete(); Tbl2.objects.filter(id__in=IDs')ho riscontrato un problema, quindi se succede a qualcun altro ... Non ha funzionato perché ID è in realtà un oggetto QuerySet. Quando ho eliminato le righe da cui proveniva, non funzionava più con altre query. La soluzione è Tbl2.objects.filter(id__in=list(IDs))- trasformalo in un elenco
Dakusan

1
A seconda del contesto, se il filtro è come "avere conteggio (xx) == yy" è più di 100 volte più veloce da usare annotate()(timeit mi ha dato 1.0497902309998608 vs 0.00514069400014705)
Olivier Pons

10

con questi modelli:

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

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

dovresti ottenere quello che vuoi usando:

table1.objects.exclude(table2=some_param)

1
Questo ti fa ancora potenzialmente estrarre MOLTI record dal database inutilmente.
Jay Taylor

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

1

Puoi scrivere una ricerca personalizzata per le query Django:

Dalla documentazione : "La partenza di Let con una semplice ricerca personalizzato Scriveremo una ricerca personalizzata ne che lavora opposta a esigere . Author.objects.filter (name__ne = 'Jack') si tradurrà in 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)]]

O meglio

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
Iterando su ogni riga di una tabella. gg
Rebs
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.