升级后,原始 sql 查询在 postgres 上将 json 字段作为字符串返回

And*_*ker 5 python django postgresql

我正在将 Django 应用程序从 2.2.7 升级到 3.1.3。该应用程序使用 Postgres 12 和 psycopg2 2.8.6。

我按照说明更改了对 的所有django.contrib.postgres.fields.JSONField引用django.db.models.JSONField,并进行了迁移。这不会对我的架构产生任何更改(这很好。)

但是,当我执行原始查询时,这些jsonb列的数据在某些时候以文本形式返回,或转换为文本。直接使用Model.objects.get(...).

import os, django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "big_old_project.settings")
django.setup()

with connection.cursor() as c:
    c.execute("select name, data from tbl where name=%s", ("rex",))
    print(c.description)
    for row in c.fetchall():
        for col in row:
            print(f"{type(col)} => {col!r}")

(Column(name='name', type_code=1043), Column(name='data', type_code=3802))
<class 'str'> => 'rex'
<class 'str'> => '{"toy": "bone"}'
Run Code Online (Sandbox Code Playgroud)

[编辑] 使用原始连接给出了预期的结果:

conn = psycopg2.connect("dbname=db user=x password=z")
with conn.cursor() as c:
    ...
<class 'str'> => 'rex'
<class 'dict'> => {'toy': 'bone'}
Run Code Online (Sandbox Code Playgroud)

尝试“注册”适配器的旧技巧不起作用,无论如何都不需要。

import psycopg2.extras
psycopg2.extras.register_json(oid=3802, array_oid=3807, globally=True)
Run Code Online (Sandbox Code Playgroud)

这个应用程序有很多历史,所以也许有什么东西踩到了 psycopg2 的脚趾?到目前为止我找不到任何东西,并且已经注释掉了所有看起来相关的东西。

浏览发行说明没有帮助。我确实使用了其他 postgres 字段,所以我无法contrib.postgres.fields从我的模型中删除所有引用。

关于为什么会发生这种情况的任何想法将不胜感激。

btm*_*lls 5

为了补充 @Andrew Backer 的有用答案,这显然是故意的。来自3.1.1 发行说明

修复了使用自定义排序QuerySet.order_by()和分组时 PostgreSQL 崩溃的问题( #31956 )。因此,使用原始 SQL 获取现在会返回字符串而不是预加载的数据。在这种情况下,您需要明确调用。JSONFielddecoderJSONFieldjson.loads()

令人惊讶的是,在错误修复版本中发现了与 API 不兼容的更改作为旁注。现在我将添加json.loads()调用,因为正如已经提到的,不能保证::json解决方法不会被破坏!