Django + Postgres:将 JSON 字符串作为 JSON 类型直接保存到模型中
Posted
技术标签:
【中文标题】Django + Postgres:将 JSON 字符串作为 JSON 类型直接保存到模型中【英文标题】:Django + Postgres: save JSON string directly into model as JSON type 【发布时间】:2017-03-28 09:17:51 【问题描述】:我有一个 Django 模型,我想在其中保存无模式键值元数据,所以我使用的是 django.contrib.postgres.fields.JSONField
。
键值数据是 Pandas 系列,默认情况下不可序列化 JSON(由于 numpy.int64、numpy.float64 类型),所以我使用方便的series.to_json()
,它返回一个已经序列化的 JSON 字符串。
为了将其保存到我的模型中,我在其上运行 json.loads
。但我知道在将数据保存到 Postgres 时会调用 json.dumps
。
如何避免这种不必要的反序列化/重新序列化步骤?
代码示例:
def create_model(pandas_series):
mdl = Model()
metadata = pandas_series.to_json() # gives a JSON string
mdl.metadata = json.loads(metadata) # string->dict, then dict->string
mdl.save()
【问题讨论】:
您能发布模型定义(至少metadata = ...
字段定义)吗?这是django.contrib.postgres.fields.jsonb.JSONField
还是第三方包?
【参考方案1】:
瓶颈在哪里
我以编程方式创建了一个包含数千个元素的字典,它看起来像这样:
d = ... , "a240": 240, "a243": 243, "a242", ...
然后我在一个循环中json.loads(json.dumps(d))
a 1000 次。平均而言,1000 次迭代需要 510 毫秒。
然后我创建了以下模型:
class JsonModel(models.Model):
jfield = JSONField()
将字典插入数据库1000次如下:
JsonModel.objects.create(jfield = d)
此操作平均耗时 21 秒。所以看起来真正的瓶颈在于将数据保存到数据库而不是序列化反序列化步骤。
因此,总而言之,保存到数据库的速度大约比 json 转储/加载慢 40 倍(但您的里程会根据字典的大小、数据库上的负载等而有所不同)。
避免额外的序列化/反序列化步骤
根据上述数字不转储/加载可能不值得。尽管如此,如果您热衷于尝试,请联系create a custom field。它可以像下面这样简单:
from django.contrib.postgres.fields import JSONField
class MyJsonField(JSONField):
def get_prep_value(self, value):
if isinstance(value, str):
return value
return super(MyJsonField,self).get_prep_value(value)
那么你的模型可以是
class JsonModel(models.Model):
metadata = MyJsonField()
....
然后在创建db记录的时候,可以传入json序列化的sting,而不是调用json.loads
mdl.metadata = metadata # no string->dict, then dict->string
【讨论】:
感谢您提供使用自定义字段的解决方案。我也感谢您进行一些性能分析,我没有发现瓶颈,只是一个多余的步骤。 很高兴被使用。是的,我们都讨厌看到多余的步骤。以上是关于Django + Postgres:将 JSON 字符串作为 JSON 类型直接保存到模型中的主要内容,如果未能解决你的问题,请参考以下文章
Django 和 postgres - 在模型字段中将数据存储为 json 的缺点
将 json 作为 celery 任务的一部分插入 postgres
使用 Django 从 Postgres 导出 JSON 时结果不一致
Postgres:使用 django 对 json 键进行值查询