使用Django,我有一个JSONField类型的字段。我想对json中的嵌套键/值进行不同的计数。使用普通字段,您可以像下面的
model.objects.values('field_name')\
.annotate(total=Count('field_name')).order_by('-total')
这不适用于JSONField。
示例模型
class Pet(models.Model):
data = JSONField()
数据示例
{
'name':'sparky',
'animal':'dog',
'diet':{
'breakfast':'biscuits',
'dinner':'meat',
}
}
尝试
Pet.objects.values('data__diet__dinner')\
.annotate(total=Count('data__diet__dinner')).order_by('-total')
例外
TypeError: unhashable type: 'list'
执行此操作的正确方法是什么?
答案 0 :(得分:2)
您可以通过jsonb_extract_path_text对象使用Func作为字段变换的替代方法:
Pet.annotate(dinner=Func(
F('data'), Value('diet'), Value('dinner'),
function='jsonb_extract_path_text')) \
.values('dinner') \
.annotate(total=Count('dinner'))
字段转换data__diet__dinner
失败的原因是,当您深入到json结构 中并在SQL中使用GROUP BY
时,Django中出现了一个错误。第一级(name
,animal
,diet
)应该可以正常工作。
原因似乎是,对于嵌套转换,Django更改了所使用的SQL语法,从单个值切换为列表,以指定json结构的路径。
这是用于非嵌套json转换(=第一层)的语法:
"appname_pet"."data" -> 'diet'
这是嵌套转换(比第一层更深)使用的语法:
"appname_pet"."data" #> ARRAY['diet', 'dinner']
在构造查询时,Django在计算所需的GROUP BY
子句时在该列表上感到窒息。这似乎不是必然的限制;对转换的支持是非常新的,这可能是尚未解决的问题之一。因此,如果您打开Django ticket,则可能只适用于某些版本。