我应该如何从 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。 (这应该是数据库中的更改,从 textjsonjsonb。) 运行 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?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 django 进行 http 获取

Django:如何在查看请求之外获取已登录的用户?

Djang

Djang_Q搜索

djang增删改查

创建djang+vue项目