Django JsonField 按两个字段过滤

问题描述

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 没有内置支持 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,根据需要扩展查询等等。

,

您好,欢迎来到 Stack Overflow!

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

案例 1

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))