【问题标题】:How to filter JSON Array in Django JSONField如何在 Django JSONField 中过滤 JSON 数组
【发布时间】:2018-08-22 20:55:35
【问题描述】:

我对在 Django 2.0.3 中过滤(postgres)JSONField 感到疯狂。 json 存储为数组。例如

tasks = [{"task":"test","level":"10"},{"task":"test 123","level":"20"}]

我尝试过的:

myModel.objects.filter("tasks__task__contains"="test")
myModel.objects.filter("tasks_task__0__contains"="test")
myModel.objects.filter("tasks__0__task__contains"="test")
myModel.objects.filter("tasks_task__0_x__contains"="test")
myModel.objects.filter("tasks__0_x__task__contains"="test")

出了什么问题? 我想要做的是一个 icontains - 但正如我已经读过的那样,现在 Django 中的 jsonfields 上不支持 icontains...

【问题讨论】:

标签: python django postgresql django-models


【解决方案1】:

正确答案应该是:

myModel.objects.filter(tasks__contains=[{"task":"test"}])

如果需要,您可能希望添加更多过滤器来缩小和加快查询速度,例如

myModel.objects.filter(Q(tasks_level=10, tasks__contains=[{"task":"test"}]))

【讨论】:

  • 我知道这是很久以前的回答,startswith 的语法是否相同?作为startswith似乎不起作用。请帮忙。
  • 此页面上的所有其他答案都有轻微的语法错误。这是适用于该数据结构的。
【解决方案2】:

过滤器中的contains 关键字非常强大。您可以使用以下命令从 Jsonb 列类型的字典数组中的任何字段中过滤掉 MyModel 中的行。

MyModel.objects.filter(tasks__contains=["task":"test"])

这是我发现在这里工作的最友好的 ORM 解决方案,没有不区分大小写的方法。 对于不区分大小写,正如您所说的那样,Django 没有用于 json 的图标,请使用

MyModel.objects.extra("") 为此,通过在 postgres 中插入“ILIKE”运算符的 SQL 查询。

【讨论】:

    【解决方案3】:
    myModel.objects.filter(tasks__contains=["task":"test"])
    

    【讨论】:

      【解决方案4】:

      我发现这里有两个问题。

      1. Django 过滤器选项用于过滤 Django 对象,而不是字段中的对象。您绝对可以过滤包含任务“测试”的对象,但您无法过滤对象中 JSONField 中的特定任务(您需要首先检索 django 对象的内容,然后在附加步骤中进行查询)

      2. 据我了解django documentation on JSONFieldcontains 运算符仅检查字典中的键或列表中的元素。将它附加到查找查询中,希望它比较一个值,就像我理解你的例子一样,因此不起作用。但是,可以使用contains 查询字典。在您的情况下,这应该适用于查询 django 对象:

        myModel.objects.filter(tasks__contains={"task": "test"})

      如果您只对一个字典感兴趣而不对其他字典感兴趣,则需要通过随后提取正确的对象来扩展此查询:

      matching_objects = myModel.objects.filter(tasks__contains={"task": "test"})
      for matching_object in matching_objects:
          for matching_task in [task for task in matching_object.tasks if "task" in task and task["task"] == "test" ]:
              print "found task", matching_task
      

      See also this related stackoverflow answer for lookups in JSONFields with contains.

      更新:Django 版本 3.1+

      以后的 Django 版本(3.1+)有一个普遍可用的 JSONField。 该字段不再纯粹绑定到 Postgres。相反,它适用于 (according to the Django documentation for version 4.0)

      MariaDB 10.2.7+、MySQL 5.7.8+、Oracle、PostgreSQL 和 SQLite(启用 JSON1 扩展)

      contains 运算符将在此处检查字典根级别的匹配键/值对。不过,它不会像问题所要求的那样选择test 123

      【讨论】:

      • 这很糟糕......问题是关于使用postgres而不是python的力量;)
      • @andilabs 仔细阅读。问题是关于 django 过滤器逻辑 - 它转换为 postgres。对于标准过滤器逻辑无法完成的所有事情,您应该求助于 python,而不是自定义 SQL,将 django ORM 映射器扔掉。关于 postgres 的注释在这里,因为 JSONField 仅在 postgres 数据库上的 django 中可用
      • 你听说过 django 的 Func,它允许你用任意 postgres 函数注释查询集吗?成功修改数据后,您可以过滤该带注释的字段。而且您也错了 JSONField 仅限于 postgres。它也可以通过django-mysql 在 MySQL 中使用,请参阅django-mysql.readthedocs.io/en/latest/model_fields/…
      • @andilabs 我们在这里谈论的是纯 django,而不是插件。我知道插件可能会添加更多功能。我也听说过Func,但我个人不喜欢在框架可以为我做的所有事情上使用自定义代码。但是请随时使用Func 使用解决方案编写您自己的答案 - 我正在根据我的经验最有效的方法编写我的答案。答案有效,可移植(如果有人决定将 JSONField 与另一个数据库一起使用,例如与您的插件一起使用)并且是可读的。
      • 对于最近浏览这个问题的人,现在可以在docs.djangoproject.com/en/4.0/topics/db/queries/…找到 JSONField 文档
      猜你喜欢
      • 2023-01-27
      • 2016-07-23
      • 2018-04-09
      • 2023-03-28
      • 2021-08-23
      • 1970-01-01
      • 2018-10-02
      • 1970-01-01
      • 2019-10-08
      相关资源
      最近更新 更多