我应该如何从 bradjasper 的 django-jsonfield 升级到 Django 的内置 jsonfield?
Posted
技术标签:
【中文标题】我应该如何从 bradjasper 的 django-jsonfield 升级到 Django 的内置 jsonfield?【英文标题】:How should I upgrade from bradjasper's django-jsonfield to Django's built-in jsonfield? 【发布时间】:2017-05-31 16:54:31 【问题描述】:我有一个使用 bradjasper 的 django-jsonfield
包的 Postgres 9.4 / Django 1.8 数据库。 (见https://github.com/bradjasper/django-jsonfield )它运行良好,但我想升级现有数据以使用 Postgres 9.6 和 Django 1.9 的内置 JSONField。 (请参阅 https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#jsonfield )这将允许对 JSON 内容进行更强大的搜索。
如何将旧数据库升级到新数据库?
我尝试过的: 我尝试将一对模式迁移插入到
将 bradjasper JSONField 转换为 TextField,包括运行迁移。 (这不应该更改数据库,因为 bradjasper 将数据存储为字符串。) 运行 Django 的dumpdata
命令。
更新了 Postgres 和 Django 版本。
运行迁移以将 TextField 转换为 Django 的 JSONField。 (这应该是数据库中的更改,从 text
或 json
到 jsonb
。)
运行 Django 的loaddata
命令。这会产生如下错误:u"[] (type <type 'unicode'>) is not a valid list for field url_methods"]: (myapp.mytable:pk=1) field_value was '[]'
我正在查看 postgresql migrating JSON to JSONB 和 Upgrade PostgreSQL JSON column to JSONB?,但希望尽量减少自定义 SQL。
【问题讨论】:
您是否还编辑/删除了现有迁移?在加载数据之前? 我在 dumpdata 之前通过 convert-to-textfield 步骤向上运行迁移,然后在 loaddata 之前运行 convert-from-textfield 迁移。编辑了尝试的步骤,使其更加清晰。 【参考方案1】:首先升级 Postgres。如果一切正常,请升级 Django。
只有当一切都按预期工作时,您才能开始编写字段迁移。
你想从:
from jsonfield import JSONField
class MyModel(models.Model):
json = JSONField()
收件人:
from django.contrib.postgres.fields import JSONField
class MyModel(models.Model):
json = JSONField()
步骤:
-
添加名为
json_new
的新 Postgres JSON 字段。
进行迁移。不要迁移。
深入研究迁移文件并编写数据迁移 (RunPython) 以填充新的 json 字段。
进行迁移。
删除旧字段。删除旧的导入。
进行迁移,迁移。
将新字段重命名为旧字段名称。 json_new
> json
.
进行迁移,迁移。
完成。
第 1 步:
使用import ... as ...
来防止冲突。您的模型将如下所示:
from jsonfield import JSONField as OldJSONField
from django.contrib.postgres.fields import JSONField
class MyModel(models.Model):
json = OldJSONField()
json_new = JSONField()
第 3 步:
您需要在迁移中RunPython
参见https://docs.djangoproject.com/en/1.10/ref/migration-operations/#runpython
另请注意如何导入模型。
实际的数据迁移将是这样的:
for obj in MyModel.objects.all()
obj.json_new = obj.json
obj.save()
第 4 - 7 步:
确保为删除和重命名创建单独的迁移。如果您更改了所有代码并创建了一个迁移,那么 Django 会认为您删除了json_new
。但是您想删除json
并将json_new
重命名为json
。微小但重要的区别。
减少迁移步骤并不难。但这需要手动编写一些代码。我很懒,喜欢 Django 为我写这段代码。
【讨论】:
我很高兴你满足了我在没有自定义 SQL 的情况下执行此操作的软要求,但单个记录的循环让我感到困扰。 (我在不同的表上有几个字段,每个表可能有几千条记录。)SQL 也比我担心的要容易。我放弃竖起大拇指,但接受我自己的答案。 您可以使用F
表达式通过单个查询在RunPython
中执行数据迁移:MyModel.objects.update(json_new=F('json'))
是的! F
可以工作,而且速度更快,数据库负载更少。【参考方案2】:
来自@tometzky 通过Upgrade PostgreSQL JSON column to JSONB? 的ALTER COLUMN 命令 做到这一点出乎意料的小麻烦:
sudo -u postgres psql -c 'ALTER TABLE mytable ALTER COLUMN "myfield" TYPE jsonb USING "myfield"::text::jsonb;'我的数据库我不需要 Django 的 loaddata / dumpdata 命令或自定义迁移。
我在让 pg_upgrade 按我想要的方式工作时确实遇到了一些问题,因为它不在默认路径上,并且想要在升级期间更改 Postgres 使用的端口。为了解决那个,我做了以下事情:
pg_ctl -D /etc/postgresql/9.4/main/stop 在 postgresql.conf 上使用sed
来更改它使用的端口
安装 Postgres 9.6
pg_ctl -D /etc/postgresql/9.6/main/stop
cd /var/log/postgresql
运行 pg_upgrade
cd 回到原来的工作目录
apt-get -y 删除 postgresql-9.4 postgresql-client-9.4 postgresql-server-dev-9.4
服务 postgresql 启动
【讨论】:
以上是关于我应该如何从 bradjasper 的 django-jsonfield 升级到 Django 的内置 jsonfield?的主要内容,如果未能解决你的问题,请参考以下文章