使用django查询设置值()来索引到JSONField

时间:2016-08-17 23:30:00

标签: json django postgresql django-queryset

我正在使用django和postgres,并且在我的模型中有一堆JSON字段(其中一些非常大且详细)。我正在从基于char的字段切换到jsonb字段,这允许我在字段内的键上filter,并且我想知道是否有任何方法可以获得等效字段通过调用查询集values方法获益。

实施例

我想做的是Car模型options JSONField,就像

qset = Car.objects.filter(options__interior__color='red')
vals = qset.values('options__interior__material')

请原谅蹩脚的玩具问题,但希望它可以解决这个问题。这里filter调用完全符合我的要求,但对values的调用似乎并不了解JSON字段的特殊性。我收到错误,因为values无法找到名为" interior"加入。是否还有一些其他语法或选项可以让我的工作成功?

似乎是对现有功能的一个非常明显的扩展,但到目前为止我没有找到任何类似于文档或堆栈溢出或谷歌搜索的引用。

编辑 - 解决方法:

在玩完之后,通过在上面的两行代码之间插入以下代码,可能会有点捏造:

qset=qset.annotate(options__interior__material=RawSQL("SELECT options->'interior'->'material'",()))

我说" fudged"因为它似乎是滥用符号而需要对整数索引进行特殊处理。

仍然希望有更好的答案。

3 个答案:

答案 0 :(得分:1)

我可以使用以下方式建议更清洁:

from django.db.models import F, Func, CharField, Value
Car.objects.all().annotate(options__interior__material =
    Func(
        F('options'),
        Value('interior'),
        Value('material'),
        function='jsonb_extract_path_text'
    ), 
)

答案 1 :(得分:1)

也许更好的解决方案(对于Django> = 1.11)是使用这样的东西:

from django.contrib.postgres.fields.jsonb import KeyTextTransform

Car.objects.filter(options__interior__color='red').annotate(
    interior_material=KeyTextTransform('material', KeyTextTransform('interior', 'options'))
).values('interior_material')

请注意,您可以嵌套KeyTextTransform表达式来提取所需的值。

答案 2 :(得分:0)

Car.objects.extra(select={'interior_material': "options#>'{interior, material}'"})
.filter(options__interior__color='red')
.values('interior_material')

您可以利用.extra()并添加postgres jsonb运算符

Postgres jsonb运算符:https://www.postgresql.org/docs/9.5/static/functions-json.html#FUNCTIONS-JSON-OP-TABLE