Я пытаюсь отфильтровать объекты модели, которые содержат пару ключ-значение из OuterRef в их JSONField со списком диктов.
У меня есть модель EntityObject с полями «тип» и «данные».
Работает без подзапроса:
EntityObject.objects.filter(
type='child',
data__list_of_dicts__contains=[{'some_key': 'value'}]
)
Также он работает внутри подзапроса без __contains (но для аннотирования нужны значения из JSONField). Например, я могу сосчитать сущности, у которых data.some_other_key равен data.some_key родительской сущности:
(EntityObject.objects
.filter(type='parent')
.annotate(data_some_key=Cast(
KeyTextTransform('some_key', 'data'), models.CharField())
)
.annotate(cnt=Subquery(
EntityObject.objects
.filter(type='child')
.annotate(data_some_other_key=Cast(
KeyTextTransform('some_other_key', 'data'), models.CharField())
)
.filter(data_some_other_key=OuterRef('data_some_key')
.values('type')
.order_by()
.annotate(cnt=Count('*'))
.values('cnt')[:1],
output_field=models.IntegerField()
))
Теперь вот что я пытаюсь сделать:
(EntityObject.objects
.filter(type='parent')
.annotate(data_some_key=Cast(
KeyTextTransform('some_key', 'data'), models.CharField())
)
.annotate(data_some_other_key=Cast(
KeyTextTransform('some_other_key', 'data'), models.CharField())
)
.annotate(cnt=Subquery(
EntityObject.objects
.filter(type='child')
.annotate(data_list_of_dicts=KeyTransform('list_of_dicts', 'data')) # not sure if this is correct
.filter(data_list_of_dicts__contains=[{OuterRef('data_some_key'): OuterRef('data_some_other_key')}]
.values('type')
.order_by()
.annotate(cnt=Count('*'))
.values('cnt')[:1],
output_field=models.IntegerField()
))
Но выдает ошибку:
TypeError: keys must be a string
Даже если я удаляю OuterRef из ключа, я получаю еще одну ошибку:
(EntityObject.objects
.filter(type='parent')
.annotate(data_some_key=Cast(
KeyTextTransform('some_key', 'data'), models.CharField())
)
.annotate(data_some_other_key=Cast(
KeyTextTransform('some_other_key', 'data'), models.CharField())
)
.annotate(cnt=Subquery(
EntityObject.objects
.filter(type='child')
.annotate(data_list_of_dicts=KeyTransform('list_of_dicts', 'data')) # not sure if this is correct
.filter(data_list_of_dicts__contains=[{'another_key': OuterRef('data_some_other_key')}]
.values('type')
.order_by()
.annotate(cnt=Count('*'))
.values('cnt')[:1],
output_field=models.IntegerField()
))
Я получаю еще одну ошибку:
TypeError: OuterRef(data_some_other_key) is not JSON serializable
Есть ли способ сделать это?
Обновление № 1
Пытался аннотировать OuterRef перед использованием:
(EntityObject.objects
.filter(type='parent')
.annotate(data_some_key=Cast(
KeyTextTransform('some_key', 'data'), models.CharField())
)
.annotate(data_some_other_key=Cast(
KeyTextTransform('some_other_key', 'data'), models.CharField())
)
.annotate(cnt=Subquery(
EntityObject.objects
.filter(type='child')
.annotate(data_list_of_dicts=KeyTransform('list_of_dicts', 'data')) # not sure if this is correct
.annotate(parent_some_key=OuterRef('data_some_key')
.annotate(parent_some_other_key=OuterRef('data_some_other_key')
.filter(data_list_of_dicts__contains=[{F('parent_some_key'): F('parent_some_other_key')}]
.values('type')
.order_by()
.annotate(cnt=Count('*'))
.values('cnt')[:1],
output_field=models.IntegerField()
))
Теперь я получаю сообщение об ошибке:
AttributeError: 'ResolvedOuterRef' object has no attribute 'contains_aggregate'
Что относится к https://code.djangoproject.com/ticket/28621
Обновление № 2
Попытка фильтрации по более простому динамическому значению. Наличие тех же ошибок, что и с OuterRef:
(EntityObject.objects
.filter(data_list_of_dicts__contains=[{F('field1'): F('field2')}])
)
Выдает:
TypeError: keys must be a string
И только динамическое значение:
(EntityObject.objects
.filter(data_list_of_dicts__contains=[{'some_key': F('field')}])
)
Выдает:
TypeError: F(id) is not JSON serializable
Создан еще один вопрос для этого Динамический Django JSONField содержит и поиск ключей