【问题标题】:Django JsonField filter by two fieldsDjango JsonField 按两个字段过滤
【发布时间】:2021-03-29 12:34:08
【问题描述】:
class Blog:
   values = JSONField(blank=True, default=list)
[
  {
    "id": 1,
    "value": "31"
  },
  {
    "id": 2,
    "value": "Hello"
  },
  ...
]

我需要获取 id 为 1 且该字段的值大于 31 的所有对象。 我已经尝试过q = queryset.filter(values__0__id=1, values__0__value_gte=31),但它仅适用于我需要的对象仅位于第一个元素中的对象。

【问题讨论】:

    标签: django django-jsonfield


    【解决方案1】:

    显然,现在Django 没有内置支持JSONField 的数组元素比较。幸运的是,Django 允许制作大量自定义人员。例如,Djangoraw SQL 功能。

    如果你使用 PostgreSQL 作为你的主数据库,你可以使用JSON Processing Functions。 JSON 处理函数中的jsonb_array_elements() 是不错的选择。

    结合以上功能,我们可以为您的情况做一些解决方法:

    # Create method that uses raw SQL within your `objects` Model Manager.
    # Create your own filters as you want. This example should be improved
    # and handle exception cases of course.
    def filter_blogs_json(json_field, sql_operator, value):
        return Blog.objects.raw(f"SELECT id, data FROM yourappname_blog CROSS JOIN jsonb_array_elements(values) AS data WHERE (data->'{json_field}')::numeric {sql_operator} {value};")
    
    # You can get raw objects queryset 
    raw_blogs_qs = filter_blogs_json('value', '>=', 31)
    
    # Then you can process it anyway you want
    filtered_blog_ids = [b.id for b in raw_blogs_qs]
    queryset = Blog.objects.filter(...).filter(id__in=filtered_blog_ids)
    

    很简单,不是吗? :)

    此外,我相信可以为JSONField 制作自己的查询集Lookup,根据需要扩展查询等等。

    【讨论】:

      【解决方案2】:

      您好,欢迎来到 Stack Overflow!

      尝试查看 Django 的 Q 对象。一些文档可用here

      案例一

      this 回答中所述,尝试使用__contains 过滤器:

      Blog.objects.filter(values__contains=[{'id': 1}])
      

      然后手动过滤第二个字段的结果。

      案例 2

      也许更好的选择是为各个值创建第二个表,例如以下模型:

      class Blog(models.Model):
          name = models.CharField(max_length=100)  # or something else
      
      
      class Value(models.Model):
          blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
          json = models.JSONField(blank=True, related_name="values")
      

      然后像这样执行搜索:

      Blog.objects.filter(Q(values__json__id=1) & Q(values__json__value__gte=31))
      

      【讨论】:

      • 当且仅当 JSONField(default=dict) 时,您的案例才有效,但在我的案例中是 dict 列表
      • @YelibayNuptebek 在第一种情况下,它应该查看列表。第二种情况是完成同样事情的一种更简洁的方法,只是将 JSON 列表分解为多个 DB 行,其中仅包含一个 JSON dict。
      • 你的第一种情况和第二种情况是什么?描述@MichalKrejčí
      • @MichalKrejčí 它不适用于这种情况,Blog.objects.filter(Q(values__json__id=1) & Q(values__json__value__gte=31)) JsonField 的工作 onlu 仅包含 json,但在这种情况下是 dict 列表
      猜你喜欢
      • 2016-07-23
      • 2016-03-25
      • 2016-06-15
      • 2021-04-03
      • 1970-01-01
      • 2018-10-02
      • 2023-03-28
      • 2020-10-08
      • 2016-11-07
      相关资源
      最近更新 更多