Существует ли джангонский способ получения объектов Django из списка с использованием по умолчанию функции all(), если список пуст?

Например, что-то вроде MyModel.objects.filter(some_value___in=[1,2], ignore_null_some_value=True) вернет MyModels с некоторыми_значениями 1 или 2, но MyModel.objects.filter(some_value__in=[], ignore_null_some_value=True) вернет все экземпляры MyModel?

Моя лучшая попытка на данный момент - сделать второй запрос к бд раньше, чтобы убедиться, что список заполнен, например:

values = <list> or MyModel.objects.values_list('some_value', flat=True))
MyModel.objects.filter(some_value__in=values)

Но это кажется неэффективным.

В любом случае вы будете оценивать запрос дважды, поэтому я предлагаю сделать просто:

filtered_qs = MyModel.objects.filter(some_value___in=[1,2])

return filtered_qs or MyModel.objects.all()

Вы могли бы сделать

q_all = MyModel.objects.all()
filtered = q_all.filter(...)
if filtered.count() == 0:
    return q_all
else:
    return filtered

Дело в том, что первый запрос (q_all) не выполняется до того, как вы запросите count(). Тогда вы знаете, сколько их всего, и можете вернуть q_all в случае чего. Из документации (https://docs.djangoproject.com/en/4.0/ref/models/querysets/):

Внешне, QuerySet может быть построен, отфильтрован, нарезан и вообще передан без фактического попадания в базу данных. Никакой активности в базе данных на самом деле не происходит, пока вы не сделаете что-то для оценки набора запросов.

Таким образом, эффективно выполняется только один запрос.

Ваш способ будет очень неэффективным, потому что эта часть должна делать сравнение множеств, что будет дорого в БД:

MyModel.objects.filter(some_value__in=values)

Вы можете просто сделать:

result = <list> or MyModel.objects.all()

Однако вы можете захотеть сделать более сложные вещи между ними. Может быть, вы хотите возвращать объекты с некоторыми value__in=[1,2], но при этом возвращать все, если эти объекты также не найдены в базе данных:

qs = MyModel.objects.filter(some_value__in=[1, 2])
result = qs if qs.exists() else MyModel.objects.all()

qs.exists() намного эффективнее, чем bool(qs), потому что он берет все данные из БД. qs.exists() посылает только одно булево и гораздо легче для БД.

Вернуться на верх