Django中的ArrayField内嵌JSONField

21

我使用包含JSONField的ArrayField插入字段时遇到了问题。

models.py

locations = ArrayField(JSONField(null = True,blank = True), blank=True, null = True)

插入

location_arr = [{"locations" : "loc1","amount":Decimal(100.00)},{"locations" : "loc2","amount":Decimal(200.25)}]
instance.locations = location_arr
instance.save()

当我这样做时,我得到了:

列“locations”的类型为jsonb [],但表达式的类型为text []

第1行:...d" = 2517,“locations”= ARRAY['{“loc...

提示:您需要重写或转换表达式。

所以我尝试使用以下方法进行转储:

import json
location_arr = [{"locations" : "loc1","amount":Decimal(100.00)},{"locations" : "loc2","amount":Decimal(200.25)}]
instance.locations = json.dumps(location_arr)
instance.save()

然后我得到了这个

LINE 1: ...d" = 2517, "locations" = '[{"loc":...

DETAIL: "[" 必须明确指定数组维度。

我正在使用:

  1. Django 1.9
  2. Python 2.7
  3. Postgres 9.4.10
  4. psycopg2 2.6.2

4
这是一个已知的漏洞 - drhagen
2
这个问题在Django==2.2a1中得到了修复。 - Artem Bernatskyi
5个回答

21

数组

首先,让我们仔细看一下来自Postgresql Arrays文档的这个重要信息。

提示:数组并不是集合;搜索特定数组元素可能是数据库设计错误的迹象。考虑使用一个单独的表,每个项目都有一行作为数组元素。这将更容易搜索,并且对于大量元素更有可能扩展。

大多数时候,您不应该使用数组。

JSONB

在Django中,JSONB可用作JSONField类型。此字段比数组字段更可扩展和灵活,并且可以更有效地进行搜索。但是,如果您经常在JSONB字段内部搜索,则与数组有关的上述语句同样适用于JSONB。

现在您的系统中有什么?一个包含JSONB字段的数组。这是一场等待发生的灾难。请规范化您的数据。

总结

那么何时使用ArrayField?

只有当您不需要在该列中进行搜索,也不需要将该列用于连接时,才会在罕见情况下使用ArrayField。


1
在极少数情况下,您不需要在该列中进行搜索,也不需要将该列用于连接。 - e4c5
我们可以使用自定义查找,例如__contains进行搜索,您觉得怎么样?https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#contains - aldesabido
而且它不搜索数组字段? - e4c5
1
这个回答已经有点过时了 - 现在Postgres支持在JSONB列上使用GIN索引(使用疯狂快速的 ? 操作符进行数组/键成员关系查询),将标签存储在列中而不是连接表中可以帮助你避免在查询期间出现大规模的连接扇出,这是一个完全合理的解决方案。 - Ben Gotow
相反的是,Ben,你正在遵循一种众所周知的 SQL 反模式,即将逗号分隔的数据放在一列中。 - e4c5
显示剩余2条评论

7
我遇到了相同的情况。以下是我解决它的方法: models.py
from django.contrib.postgres.fields.jsonb import JSONField as JSONBField
location = JSONBField(default=list,null=True,blank=True)

插入。
model_object.location = [{"locations" : "loc1","amount":Decimal(100.00)},{"locations" : "loc2","amount":Decimal(200.25)}]

更新。
model_object.location.append({"locations" : "loc1","amount":Decimal(100.00)})
model_object.save()

这对我在以下环境中有效: Django - 2.0.2 Postgres - 9.5 psycopg2 - 2.7.4 Python - 3.4.3

现在,您如何在JSONBField中搜索特定位置,比如说locations="loc1"? - Khatri

4

您可以通过使用JSONField作为列字段类型,将list作为根元素,来避免这个问题。

from django.contrib.postgres.fields import JSONField
class MyDBArray(models.Model):
    array_data = models.JSONField(default=list)

my_db_array = MyDBArray(array_data=[1, 2, 3])
my_db_array.save()

save方法中,您需要验证array_data字段实际上是类似于列表的。


1
这个问题已在最新的Django 2.2a1未发布版本中得到修复。 pip install Django==2.2a1 PS 我相信它也将适用于版本>= 2.2a1

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接