为啥 Django 将 postgres JSONField 值作为字符串返回?

Posted

技术标签:

【中文标题】为啥 Django 将 postgres JSONField 值作为字符串返回?【英文标题】:Why does Django return postgres JSONField value as string?为什么 Django 将 postgres JSONField 值作为字符串返回? 【发布时间】:2017-08-03 22:18:57 【问题描述】:

环境:

Django 1.10.6 psycopg2 2.7.1 通过 Homebrew 在 macOS Sierra 上安装 PostgreSQL 9.6.2 通过 Homebrew 安装的 Python 3.6.0

示例模型:

from django.db import models
from django.contrib.postgres.fields import JSONField


class Foo(models.Model):
    data = JSONField()

当我尝试创建一个对象时,一切都按预期工作:

from myapp.models import Foo
x = Foo()
x.data = 'key1': 'value1'
x.save()

查询按预期工作:

Foo.objects.filter(data__key1='value1').count()
# 1

但是,当我尝试从对象中检索该数据时,.data 属性的值是一个字符串:

from myapp.models import Foo
x = Foo.objects.get(id=1)
x.data
# '"key1": "value1"'
type(x.data)
# str

我希望在这里得到一个字典。尝试保存对象时,问题会递归地变得更糟

x.save()
x = Foo.objects.get(id=1)
x.data
# '"\\"key1\\": \\"value1\\""'
x.save()
x = Foo.objects.get(id=1)
x.data
# '"\\"\\\\\\"key1\\\\\\": \\\\\\"value1\\\\\\"\\""'

【问题讨论】:

这不应该发生。你能展示你的完整模型吗?您是否有任何验证器、自定义保存方法或附加到保存事件的任何信号? 我开始从项目中安装的其他应用程序向后工作,发现罪魁祸首是这个应用程序github.com/jjkester/django-auditlog。当我从 MIDDLEWARE 和 INSTALLED_APPS 中删除它时,一切都按预期工作。进一步看,该项目需要 django-jsonfield 并且两者之间一定存在一些不兼容 事实上它已经是该项目中的一个未解决问题github.com/jjkester/django-auditlog/issues/71 【参考方案1】:

原来你不能在同一个项目中使用 django-jsonfield 和 Django 的原生 JSONField,否则你会遇到问题中描述的奇怪行为

https://bitbucket.org/schinckel/django-jsonfield/issues/57/cannot-use-in-the-same-project-as-djangos

【讨论】:

【参考方案2】:

对我来说,问题是数据库是从备份创建的,列类型设置为text,而它本应为jsonjsonb

清除所有无效的 json,然后使用以下内容更改列类型:

ALTER TABLE t ALTER COLUMN j TYPE jsonb USING j::text::jsonb;

(感谢https://***.com/a/28076909/2362877)

【讨论】:

以上是关于为啥 Django 将 postgres JSONField 值作为字符串返回?的主要内容,如果未能解决你的问题,请参考以下文章

使用 postgres 在 Django 中高效存储 Json

Django 和 postgres - 在模型字段中将数据存储为 json 的缺点

将 json 作为 celery 任务的一部分插入 postgres

使用 Django 从 Postgres 导出 JSON 时结果不一致

Postgres:使用 django 对 json 键进行值查询

在 postgres,Django 中保存大型 json 对象