После обновления до Django 3.2 мои аннотации на полях `ArrayAgg` не работают
У меня есть довольно сложный метод модели, который прекрасно работал до обновления до Django 3.2.8. Он выглядит следующим образом:
@classmethod
def get_inbox_for_user(cls, user: User) -> 'models.QuerySet[ShareRequest]':
user_principals_ids = list(user.principals.values_list('id', flat=True))
annotated_share_requests = cls._default_manager\
.annotate(
registered_staff_ids=ArrayAgg(
'contact__registered_staffing__staff_user',
distinct=True,
)
)\
.annotate(
primary_registered_staff_ids=ArrayAgg(
'contact__registered_staffing__staff_user',
filter=models.Q(contact__registered_staffing__is_primary=True),
distinct=True,
)
)
filtered_shared_requests = annotated_share_requests\
.filter(
(models.Q(primary_registered_staff_ids__isnull=True) & models.Q(registered_staff_ids__contains=[user.id]))
| (models.Q(primary_registered_staff_ids__isnull=True) & models.Q(registered_staff_ids__overlap=user_principals_ids))
| models.Q(primary_registered_staff_ids__contains=[user.id])
| models.Q(primary_registered_staff_ids__contained_by=user_principals_ids)
)
return filtered_shared_requests
Опустим детали, важной частью являются мои утверждения аннотаций и дальнейшая фильтрация по ним.
Из примера ниже видно, что registered_staff_ids
приводит к [None]
, что выглядит как часть проблемы:
In [39]: annotated_share_requests.first().registered_staff_ids
Out[39]: [None]
Я смог исправить это, предоставив дополнительный фильтр для моего оператора annotate, превратив это выражение в:
annotated_share_requests = cls._default_manager\
.annotate(
registered_staff_ids=ArrayAgg(
'contact__registered_staffing__staff_user',
filter=models.Q(contact__registered_staffing__staff_user__isnull=False),
distinct=True,
)
)\
...
Теперь результат выглядит так:
In [40]: annotated_share_requests.first().registered_staff_ids
Out[40]: []
Однако дальнейшая фильтрация (в частности, поиск __overlap
и __contained_by
не работает, например:
In [56]: annotated_share_requests.values_list('primary_registered_staff_ids', flat=True)
Out[56]: <QuerySet [[], []]> # looks great
In [57]: annotated_share_requests.values_list('registered_staff_ids', flat=True)
Out[57]: <QuerySet [[], []]> # looks great
In [58]: user_principals_ids
Out[58]: [] # looks great
# BUT!
In [59]: annotated_share_requests.filter(registered_staff_ids__overlap=user_principals_ids)
Out [59]: FieldError: Cannot resolve expression type, unknown output_field
# AND SIMILARLY!
In [61]: annotated_share_requests.filter(primary_registered_staff_ids__contained_by=user_principals_ids)
Out [62]: FieldError: Cannot resolve expression type, unknown output_field
Интересно то, что это кажется проблемой только в случае пустого массива с правой стороны сравнения, так что это работает:
In [76]: annotated_share_requests.filter(primary_registered_staff_ids__contained_by=[1])
Out[76]: <QuerySet []>
In [77]: annotated_share_requests.filter(registered_staff_ids__overlap=[1])
Out[77]: <QuerySet []>
Ищет любые указатели.