我正在将Django应用程序从2.2.7升级到3.1.3。该应用程序使用Postgres 12和psycopg2 2.8.6。
我按照说明将所有的django.contrib.postgres.fields.JSONField
引用更改为django.db.models.JSONField
,并进行和运行迁移。这不会对我的模式产生任何更改(这很好)。
然而,当我执行原始查询时,这些jsonb
列的数据在某个时候作为文本返回,或者转换为文本。
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"}'
[edit]使用原始连接可以得到预期的结果:
conn = psycopg2.connect("dbname=db user=x password=z")
with conn.cursor() as c:
...
<class 'str'> => 'rex'
<class 'dict'> => {'toy': 'bone'}
尝试“注册”适配器的老把戏不起作用,而且无论如何也不应该需要。
import psycopg2.extras
psycopg2.extras.register_json(oid=3802, array_oid=3807, globally=True)
这个应用程序有很多历史,所以也许有什么东西在踩psycopg2的脚趾?我到目前为止找不到任何东西,并评论了所有似乎无关紧要的东西。
查看发行说明也没有帮助,我确实使用了其他postgres字段,所以我不能从我的模型中删除所有对contrib.postgres.fields
的引用。
任何关于为什么会发生这种情况的想法都将受到极大的赞赏。
4条答案
按热度按时间ijxebb2r1#
为了补充@ AndrewBacker的回答,这显然是故意的。
修正了在PostgreSQL上使用自定义
decoder
(#31956)按JSONField
排序和分组时QuerySet.order_by()
崩溃。因此,使用原始SQL获取JSONField
现在返回字符串而不是预加载的数据。在这种情况下,您需要显式调用json.loads()
。在一个bugfix发行版中发现API不兼容的改变是令人惊讶的。现在我将添加
json.loads()
调用,因为正如已经提到的,不能保证::json
解决方案不会中断!dgiusagp2#
好的,这似乎是他们在django 3.1.1中引入的一个修改,为了修复其他bug。它从底层连接中取消了
jsonb
转换器的注册,这在IMO中是很糟糕的。Django问题:第一个“修复”破坏了这个基本功能沿着拒绝了原始sql的用例,第二个是声明破坏无效。
要解决这个问题,你可以制作你自己的原始游标,django不会搞砸,或者在原始sql中转换你的字段。至少,直到他们也破坏它!
hts6caw33#
谢谢你的这篇有帮助的文章!我的解决方案看起来像这样:
70gysomp4#
@Sascha Rau,你的帖子真的很有帮助。为了可能保存别人一点时间,我注意到这对你提出的解决方案至关重要:
另外,对于Django项目数据库的这个设置配置:
可以使用
conn = connections['default']
引用与默认项目数据库的连接