Postgres:使用 django 对 json 键进行值查询
Posted
技术标签:
【中文标题】Postgres:使用 django 对 json 键进行值查询【英文标题】:Postgres: values query on json key with django 【发布时间】:2017-07-29 06:50:03 【问题描述】:我需要在 django 1.10 中对 postgres 支持的 jsonfield 上的嵌套键执行 values/values_list 查询 例如。
class AbcModel(models.model):
context = fields.JSONField()
如果它有如下值:
'lev1':
'lev': 2
我想运行类似的查询
AbcModel.objects.values('context__lev1__lev2').distinct()
AbcModel.objects.values_list('context__lev1__lev2', flat=True).distinct()
编辑: JSON 字段是来自 django.contrib.postgres.fields 的官方 django JSONField
【问题讨论】:
那么您面临的问题是什么? django 返回错误 FieldError: Cannot resolve keyword 'lev1' into field。不允许加入“上下文”。 这是您数据库中的准确 json 表示吗? 什么意思? Postgres 数据类型是 Jsonb。结构相同的是数据库和这里显示的内容 【参考方案1】:所以我找到了一个解决方案,这适用于 django 1.10 及更高版本。 我使用 KeyTransform 来注释和提取下一个键,并在其上做了一个 values_list。
from django.contrib.postgres.fields.jsonb import KeyTransform
extracted_query = AbcModel.objects.annotate(lev1=KeyTransform('lev1', 'context')).annotate(lev2=KeyTransform('lev', 'lev1'))
这个查询允许我使用 lev1 和 lev2 作为模型中的普通字段,所以我可以对字段执行值、values_list 或任何其他有效查询。
Django 1.11 允许将两个 Transforms 嵌套在一个注释中,不确定 1.10 关于嵌套,因为我已升级到 1.11
【讨论】:
KeyTransform
被认为是 Django 中非公共 api 的一部分吗?从 Django 2 开始,似乎在文档中的任何地方都没有提到它。
它可以被视为一个非公共 api,因为它没有在任何地方记录,但同时,我发现 postgres 特定的东西不像 django 的其他部分那样有很好的记录,但它不太可能要更改,因为它会影响太多事情,请查看此错误报告,提出相同的观点code.djangoproject.com/ticket/29482
@Shaumux 如果它是动态的,我们如何评估lev1
键?意思是lev
是像OuterRef
一样从Subquery
传递的密钥
@NwawelAIroume 我不确定您所说的动态到底是什么意思,键是动态的吗?您应该仍然可以使用 Cast 函数转换为 JSON 类型并使用相同的方法,但可能会有很多嵌套调用
@Shaumaux 我注意到Cast
有助于提取整个字典。但我只想提取字典键的值。我想做类似annotate(lev1=KeyTransform(OuterRef("external_model_column_value"), 'context'))
【参考方案2】:
这并不理想,但我能够通过将 json 字段添加为额外字段然后在该额外字段上调用值来实现此功能:
AbcModel.objects.extra(select=
"extra_field": "context->'lev1'->'lev2'"
).values('extra_field').distinct()
AbcModel.objects.extra(select=
"extra_field": "context->'lev1'->'lev2'"
).values_list('extra_field', flat=True).distinct()
【讨论】:
如何让->
运算符工作?我想用它而不是很多KeyTransform
,但是得到这个错误:django.db.utils.ProgrammingError: operator is not unique: unknown -> unknown LINE 1: SELECT ('step_data'->'step_data'->'workshop') AS "w" FROM "w... ^ HINT: Could not choose a best candidate operator. You might need to add explicit type casts.
@dirkgroten KeyTransform 将使用 -> 运算符,如果您使用像 'step_data' -> 'lev1' 这样的单级提取,如果您使用嵌套或链式注释来提取,它将使用 #> 运算符嵌套数据,例如。 'step_data' -> 'lev 1' -> 'lev2'
是的,我明白了,感谢您的回复。但是我遇到的问题是使用上面显示的显式 select
命令时。使用->
运算符进行查询会显式抛出我显示的错误(operator is not unique
)。以上是关于Postgres:使用 django 对 json 键进行值查询的主要内容,如果未能解决你的问题,请参考以下文章
使用 Django 从 Postgres 导出 JSON 时结果不一致
使用 postgres 在 Django 中高效存储 Json
Django + Postgres:将 JSON 字符串作为 JSON 类型直接保存到模型中
在 postgres,Django 中保存大型 json 对象