Django в / не в запросе

100

Я пытаюсь понять, как написать запрос стиля «не в» в 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?

Турбо
источник

Ответы:

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

Функция исключения работает как Not оператор, о котором вы просили. Атрибут flat = Trueсообщает table2запросу о возврате value_listодноуровневого списка. Итак ... в конце вы получаете список IDsиз таблицы 2, в котором вы собираетесь указать пользователю условие table1, которое будет отклонено функцией исключения.

Harph
источник
3
У меня также были проблемы с конструктором списков [table2 ...] -> list (table2 ...) работал у меня.
RickyA
3
исправление: table1.objects.exclude (id__in = table2.objects.filter (your_condition) .values_list ('id', flat = True))
Ричард
1
Пытался использовать это решение и столкнулся с проблемой, поэтому, если это произойдет с кем-то еще ... Objs=Tbl1.objects.filter(...); IDs=Objs.values_list('id', flat=True); Objs.delete(); Tbl2.objects.filter(id__in=IDs')Это не сработало, потому что идентификаторы на самом деле являются объектом QuerySet. Когда я удалил строки, из которых он произошел, он больше не работал с другими запросами. Решение Tbl2.objects.filter(id__in=list(IDs))- превратите его в список
Дакусан
1
В зависимости от контекста, если фильтр похож на «имеющий count (xx) == yy», его использовать более чем в 100 раз быстрее annotate()(timeit дал мне 1,0497902309998608 против 0,00514069400014705)
Olivier Pons
10

с этими моделями:

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
При этом вы потенциально можете без надобности извлекать МНОГО записей из базы данных.
Джей Тейлор
5
table1.objects.extra(where=["table1.id NOT IN (SELECT table2.key_to_table1 FROM table2 WHERE table2.id = some_parm)"])
ibz
источник
1

Вы можете написать собственный поиск для запросов Django:

Из документации : «Давайте начнем с простого пользовательского поиска Мы будем писать пользовательские подстановок нэ , который работает напротив взыскать . Author.objects.filter (name__ne =„Jack“) переведет к 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
Blairg23
источник
-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