Django JSONField字典列表在子查询中“包含”过滤器

时间:2019-01-08 16:47:07

标签: django postgresql

我正在尝试过滤包含对象列表的JSON对象中包含来自OuterRef的键值对的模型对象。

我有一个模型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 dynamic contains and key lookups

创建了另一个问题

0 个答案:

没有答案