Django в / не в запиті


100

Я намагаюся розібратися, як написати запит у стилі "не в" в джанго. Наприклад, структура запитів, про які я думаю, виглядала б так.

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

Як виглядатиме синтаксис джанго, якщо припустити моделі, що називаються 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якому буде відмовлено функцією виключення.


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
Залежно від контексту, якщо фільтр на кшталт "маючи кількість (xx) == yy", його використовувати більш ніж у 100 annotate()разів (timeit дав мені 1,0497902309998608 проти 0,00514069400014705)
Олів'є Понс,

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
Це все ще дозволяє потенційно витягувати багато записів із db без потреби.
Джей Тейлор

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

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

-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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.