Чтобы использовать предварительно выбранные группы, вы должны избегать фильтрации набора запросов groups.all()
, так как это создаст новый запрос.Итак:
def has_group(user, group_name):
groups = user.groups.all()
return group_name in [g.name for g in groups]
Обратите внимание, что это не обязательно повышает производительность по сравнению с отдельным запросом для пользователя.Обязательно выполните некоторое профилирование.
Если у вас есть тысячи вызовов на has_group
на отчет, вы можете сохранить список имен групп в атрибуте пользователя, сэкономив еще несколько мс на отчет:
def has_group(user, group_name):
groups = user.groups.all()
if not hasattr(user, 'group_names'):
user.group_names = [g.name for g in groups]
return group_name in user.group_names
И, наконец, если вы знаете, что для большинства пользователей набора запросов вы будете вызывать has_user
, вы можете предварительно инициализировать атрибут group_names
для всех пользователей, чтобы сохранить вызов функции has_group
для каждого запроса ииспользовать if group_name in user.group_names
напрямую вместо has_group(user, group_name)
.
Я был удивлен, увидев в неформальном тестовом прогоне, что при кэшировании списка сэкономлено около 10% на 100 000 вызовов, а добавление запроса на членство еще больше сэкономило колоссальные 80%.довести общую экономию на порядок.Но если у вас всего несколько сотен вызовов в отчете, эффект, вероятно, незначителен.
Еще один способ сэкономить время - сделать ваши предварительные выборки проще, поскольку prefetch_related
- довольно тяжелая операция (вот почемучасто имеет смысл делать целевые запросы к базе данных, а не перетаскивать все эти данные из базы данных в объекты Python).Поэтому, если у вас много пользователей (или групп), и вы знаете, что вам нужны только имена групп, а не полноценные объекты групп, не используйте
users = User.objects.prefetch_related('groups')
Используйте это вместочтобы получить список Group
объектов, а не QuerySet
, только с предварительно выбранным полем name
:
users = (User.objects
.prefetch_related(
Prefetch('groups',
queryset=Group.objects.only('name'),
to_attr='group_list'
)
)
)
Затем создайте список имен групп, как раньше:
for u in users:
u.group_names = [g.name for g in u.group_list]
К сожалению, пока (v2.1.5) невозможно предварительно выбрать только имена групп, например, с помощью values_list
в наборе запросов объекта предварительной выборки.