Как выполнить условие OR в наборе запросов django?

Я хочу написать запрос Django, эквивалентный этому запросу SQL:

SELECT * from user where income >= 5000 or income is NULL.

Как построить фильтр наборов запросов Django?

User.objects.filter(income__gte=5000, income=0)

Это не работает, потому что это AND фильтры. Я хочу OR фильтры, чтобы получить объединение отдельных наборов запросов.

Ответ 2

Поскольку QuerySets реализует оператор Python __or__ (|) или объединение, он просто работает. Как и следовало ожидать, | Двоичный оператор возвращает QuerySet так что order_by(), .distinct() и другие фильтры .distinct() могут быть добавлены до конца.

combined_queryset = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)
ordered_queryset = combined_queryset.order_by('-income')

Обновление 2019-06-20: теперь это полностью документировано в справочнике по API QuerySet Django 2.1. Более историческое обсуждение можно найти в билете DjangoProject # 21333.

Ответ 3

Оба варианта уже упомянуты в существующих ответах:

from django.db.models import Q
q1 = User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

и

q2 = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)

Однако, похоже, существует некоторая путаница в отношении того, какой из них предпочтительнее.

Дело в том, что они идентичны на уровне SQL, поэтому не стесняйтесь выбирать, что вам нравится!

Поваренная книга Django ORM рассказывает об этом более подробно, вот соответствующая часть:


queryset = User.objects.filter(
        first_name__startswith='R'
    ) | User.objects.filter(
    last_name__startswith='D'
)

ведет к

In [5]: str(queryset.query)
Out[5]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
"auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
"auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
"auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

и

qs = User.objects.filter(Q(first_name__startswith='R') | Q(last_name__startswith='D'))

ведет к

In [9]: str(qs.query)
Out[9]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
 "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
  "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
  "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
  WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

источник: django-orm-cookbook