У меня довольно сложный запрос, и я бьюсь головой об этом.
Позвольте мне объяснить сценарий.
Я хочу вернуть набор запросов, помеченный количеством дел, которые user
завершил, когда они сертифицированы.
Представь, что у моего пользователя три роли. a_delegate
, b_certified
и c_accredited
.
a_delegate
говорит нам, что user
готовится к курсу a
,
мы не хотим считать завершенные дела по курсу a
.
b_certified
сообщает нам, что user
прошел обучение по курсу b
и сертифицирован. Нам нужно посчитать эти завершенные дела
c_accredited
говорит нам, что user
продвинулся дальше своего обучения для курса b
. Нам нужно посчитать эти завершенные дела
Я использую встроенную модель User
, которую поставляет Django, ничего особенного. Роли - это просто название встроенной модели Group
, которую поставляет Django снова.
Теперь я знаю, что это, вероятно, получит "просто написать raw sql" комментарии, и это нормально. Я не отказываюсь от возможности использования сырых SQL здесь. Я просто хочу знать, есть ли способ сделать это сначала с ORM.
У меня есть эта функция, которая отображает входные данные для соответствующих ролей.
def convert_filter_str(str: str) -> Tuple:
"""
Converts expected filters into course names and returns them
and the relevant roles as a Tuple
"""
APPLIANCES: Dict = {
'a': 'Type A',
'b': 'Type B',
'c': 'Type C',
}
ROLES: Dict = {
'a': ['a_certified', 'a_accredited'],
'b': ['b_certified', 'b_accredited'],
'c': ['c_certified', 'c_accredited'],
}
filters: List = str.split(',')
converted_filters: List = []
converted_roles: List = []
for filter in filters:
filter = filter.strip()
converted_item = APPLIANCES[filter]
converted_role = ROLES[filter]
converted_filters.append(converted_item)
converted_roles.append(converted_role)
return converted_filters, converted_roles
Итак, если пользователь ввел фильтр как a,b
, тогда:
converted_filters
должен вернуться ['Type A', 'Type B']
converted_roles
должен вернуться [['a_certified', 'a_accredited'], ['b_certified', 'b_accredited']]
Если мы рассмотрим то, что я упоминал ранее, User
имеет три роли. a_delegate
, b_certified
и c_accredited
, поэтому в соответствии с фильтрами, приведенными выше, мы должны смотреть только на возврат подсчета для случаев для Type B
.
Для краткости у меня уже есть Queryset с этим пользователем.
Мне нужно отфильтровать это в зависимости от ввода пользователя, поэтому, чем больше фильтров они применяют, тем больше добавляется отсчетов.
Я думал об использовании Суммы со списком агрегатов, но это выдает django.db.utils.ProgrammingError: can't adapt type 'Count'
final_qs: User = user.annotate(
completed_cases=(Sum(
[Count(
'patientcase',
filter=Q(
groups__name__in=role_filter[i]
)
) for i in range(len(role_filter))],
output_field=IntegerField()
))
)
Я также подумал об использовании Sum с генератором агрегатов количества, но это выдает psycopg2.ProgrammingError: can't adapt type 'generator'
final_qs: User = user.annotate(
completed_cases=(Sum(
(Count(
'patientcase',
filter=Q(
groups__name__in=role_filter[i]
)
) for i in range(len(role_filter))),
output_field=IntegerField()
))
)
Есть ли способ заставить это работать через ORM?