Python 2到3的Django迁移导致字段参数类型更改

16

我们正在将一个 Django 项目从 Django 1.8 -> 2.1 和 Python 2.7 -> 3.6 进行迁移。

在旧版本的项目中,有像这样的 Django 模型,例如:

# models.py

from django.db import models

class RowStatusModel(models.Model):
    active = models.BooleanField(default=True, db_column='is_active')
    # ...
    class Meta:
        abstract = True

请注意本模块中没有使用from __future__ import unicode_literals。 这意味着db_column是Python 2的str,对应于Python 3中的bytes。最初的迁移文件0001_initial.py如下所示:

# 0001_initial.py

operations = [
    # ...
    ('row_ef', models.BooleanField(default=True, db_column=b'is_active')
    # ...
]

注意字节字符串b'is_active',我认为这是Django出于更加明确的目的而做出的,但不确定。

现在,在使用2to3转换大多数代码库并运行makemigrations后,Python 3将字符串文本视为Python 2中的unicode类型,并因此为每个继承自RowStatusModel的模型生成一个以字符串文本为列名的迁移:

# migrations/0023_auto_20180827_1955.py 
migrations.AlterField(
    # ...
    field=models.BooleanField(default=True, db_column='is_active')
), # ...

当运行./manage.py migrate时,这会对数据库端产生什么影响(如果有的话)?这个“更改”仅仅是在Python端吗?还会产生什么副作用?


数据库引擎为django.db.backends.postgresql


我知道我们可以克隆RDS实例并恢复到以前的状态,如果migrate导致了立即的问题,但我更担心会引入一些微妙的问题,这些问题直到很久以后才会被发现。


2
正如在那张工单的最后一条评论中所指出的那样,您可以编辑现有的迁移来删除字符串上的 b 前缀。如果选择生成新的迁移,它将不会产生任何影响。 - solarissmoke
2
@BradSolomon 在我们迁移到Python3时,这就是我们所做的(修改现有的迁移)。没有生成新的迁移文件,我们也没有遇到任何问题(后端通常是Postgres)。 - user2390182
1个回答

12

在我提出这个问题后,我发现一个Django工单,其中Django开发人员的建议是编辑任何包含(Python 3)字节文字的旧版迁移文件(例如0001_initial),删除b并将它们转换为Python 3中的字符串文字。

编辑迁移以解决此问题是安全的。

从那里开始,您应该能够删除使用python3 ./manage.py makemigrations创建的迁移模块,并重新执行该命令,这时就不会再出现该参数类型问题。

我使用以下方法对所有实例的'db_column=b'进行了大规模查找和替换,用'db_column='替换。当然,在提交之前,您应该绝对检查git diff

grep -nrl "db_column=b" apps | xargs sed -i "s/db_column=b/db_column=/g"

2
您可以使用 sqlmigrate 命令检查迁移对数据库的影响。这些迁移很可能不会对数据库产生任何影响。即使字段的 choices 参数发生更改,Django 也会生成迁移,但不会对数据库产生任何影响。还有其他一些“无需 SQL”的迁移情况。 - smido
1
在更复杂的情况下,如果编辑所有现有的迁移需要太多时间,那么值得考虑只是生成这些没有效果的迁移,以使Django保持愉快,并像往常一样继续(提交,迁移等)。 - smido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,