【问题标题】:how to write a query to get find value in a json field in django如何编写查询以在 django 的 json 字段中查找值
【发布时间】:2012-05-13 18:46:45
【问题描述】:

我的数据库中有一个 json 字段,类似于

jsonfield = {'username':'chingo','reputation':'5'}

如何编写查询,以便查找用户名是否存在。像

username = 'chingo'
query = User.objects.get(jsonfield['username']=username)

我知道上面的查询是错误的,但我想知道是否有办法访问它?

【问题讨论】:

    标签: django django-models django-queryset


    【解决方案1】:

    如果你使用的是 django-jsonfield 包,那么这很简单。假设你有一个这样的模型:

    from jsonfield import JSONField
    class User(models.Model):
        jsonfield = JSONField()
    

    然后要搜索具有特定用户名的记录,您可以这样做:

    User.objects.get(jsonfield__contains={'username':username})
    

    【讨论】:

    • 显然它不适用于最后一个(1.0.3)jsonfield。
    • 那么解决办法是什么。我正在使用 1.0.3 @VladE.Borovtsov
    • 嗯,我记得我找到了一些不好的解决方案。但最终停止使用该字段。很久以前在 postgres 中使用原生 json 字段。 @ShashankHegde
    • 是的。即使我会尝试从 mysql 迁移到 postgres 并开始使用其内置的 JsonField 和 django 1.9。感谢回复
    • 你可以使用User.objects.get(jsonfield__contains='"username":"{}"'.format(username))
    【解决方案2】:

    从 Django 1.9 开始,您已经能够使用 PostgreSQL 的原生 JSONField。这使得搜索 JSON 变得非常简单。在您的示例中,此查询将起作用:

    User.objects.get(jsonfield__username='chingo')
    

    如果您有旧版本的 Django,或者您正在使用 Django JSONField 库与 MySQL 或类似的东西兼容,您仍然可以执行查询。

    在后一种情况下,jsonfield 将被存储为文本字段并在带入 Django 时映射到字典。在数据库中,你的数据会这样存储

    {"username":"chingo","reputation":"5"}
    

    因此,您可以简单地搜索文本。您在这种情况下的查询是:

    User.objects.get(jsonfield__contains='"username":"chingo"')
    

    【讨论】:

      【解决方案3】:

      这种用法有点反模式。此外,它的实现不会有常规性能,也许很容易出错。
      当您需要通过字段查找时,通常不要使用 jsonfield。正如 Daniel 指出的那样,使用 RDBMS 提供的方式或 MongoDB(内部运行在更快的 BSON 上)。

      由于deterministic of JSON format, 您可以通过使用contains 来实现它(regex 在处理多个'\' 时会出现问题,甚至更慢),我认为以这种方式使用 username 并不好,所以请改用 name

      def make_cond(name, value):
          from django.utils import simplejson 
          cond = simplejson.dumps({name:value})[1:-1] # remove '{' and '}'
          return ' ' + cond # avoid '\"'
      
      User.objects.get(jsonfield__contains=make_cond(name, value))
      

      只要有效果

      • 使用相同转储实用程序的 jsonfield(此处为 simplejson
      • namevalue 并没有太特别 (目前我不知道任何egde-case,也许有人可以指出它出)
      • 您的 jsonfield 数据没有损坏(虽然不太可能)

      其实我在做一个可编辑的jsonfield,在考虑是否支持这样的操作。否定证明就是上面说的,感觉有点黑魔法,嗯。

      【讨论】:

      • 使用 import jsonjson.dumps(... simplejson 已弃用。顺便说一句,这不适用于旧版本的 postgres!
      【解决方案4】:

      2019:正如@freethebees 指出的那样,现在很简单:

      User.objects.get(jsonfield__username='chingo')
      

      但是正如文档示例中提到的,您可以深入查询,如果 json 是一个数组,您可以使用整数对其进行索引:

      https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/#querying-jsonfield

      >>> Dog.objects.create(name='Rufus', data={
      ...     'breed': 'labrador',
      ...     'owner': {
      ...         'name': 'Bob',
      ...         'other_pets': [{
      ...             'name': 'Fishy',
      ...         }],
      ...     },
      ... })
      >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None})
      
      >>> Dog.objects.filter(data__breed='collie')
      <QuerySet [<Dog: Meg>]>
      
      >>> Dog.objects.filter(data__owner__name='Bob')
      <QuerySet [<Dog: Rufus>]>
      
      >>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
      <QuerySet [<Dog: Rufus>]>
      

      虽然这是针对 postgres 的,但我相信它在 MySQL 等其他数据库中的工作原理是一样的

      【讨论】:

        【解决方案5】:

        如果你使用 PostgreSQL,你可以使用原始 sql 来解决问题。

        username = 'chingo'
        SQL_QUERY = "SELECT true FROM you_table WHERE jsonfield::json->>'username' = '%s'"
        User.objects.extra(where=[SQL_EXCLUDE % username]).get()
        

        you_table 是数据库中表的名称。

        使用 JSON 时的任何方法,例如使用纯文本 - 看起来都非常糟糕。 所以,我也认为你需要一个更好的数据库架构。

        【讨论】:

          【解决方案6】:

          这是我发现的解决您问题的方法:

          search_filter = '"username":{0}'.format(username)
          query = User.objects.get(jsonfield__contains=search_filter)
          

          希望这会有所帮助。

          【讨论】:

            【解决方案7】:

            你不能那样做。对结构化数据使用普通数据库字段,而不是 JSON blob。

            如果您需要搜索 JSON 数据,请考虑使用 MongoDB 等 noSQL 数据库。

            【讨论】:

            • 相当过时的答案
            猜你喜欢
            • 1970-01-01
            • 2019-12-23
            • 2019-06-23
            • 2019-03-20
            • 2020-06-19
            • 2022-10-01
            • 1970-01-01
            • 2016-06-14
            • 1970-01-01
            相关资源
            最近更新 更多