Существует ли джангонский способ получения объектов 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() посылает только одно булево и гораздо легче для БД.