在 Django 数据迁移中引用外部变量

Kur*_*aki 6 django django-migrations

在迁移中使用模型时,在 Django 中我们可以使用apps.get_model()来确保迁移将使用模型的正确“历史”版本(就像定义迁移时一样)。但是我们如何处理从代码库导入的“常规”变量(而不是模型)?

如果我们从另一个模块导入变量,我们将来可能会遇到问题。例如:

  1. 如果将来有一天我们删除该变量(因为我们更改了实现),这将破坏迁移。因此,我们将无法在本地重新运行迁移来从头开始重新创建数据库。
  2. 如果我们修改变量(例如,更改列表中的值),当我们在现有数据库上运行反向操作时,这将产生意想不到的效果。

所以问题是:编写迁移的最佳实践是什么?我们是否应该始终对值进行硬编码而不导入外部变量?


例子

假设我想简单地使用我在代码库中某处定义的变量来修改字段的值。例如,我想将所有普通用户变成管理员。我将用户角色存储在枚举 ( UserRoles) 中。编写迁移的一种方法是:

from django.db import migrations
from user_roles import UserRoles


def change_user_role(apps, schema_editor):
    User = apps.get_model('users', 'User')
    users = User.objects.filter(role=UserRoles.NORMAL_USER.value)
    for user in users:
        user.role = UserRoles.ADMIN.value

    User.objects.bulk_update(users, ["role"])


def revert_user_role_changes(apps, schema_editor):
    User = apps.get_model('users', 'User')
    users = User.objects.filter(role=UserRoles.ADMIN.value)
    for user in users:
        user.role = UserRoles.NORMAL_USER.value

    User.objects.bulk_update(users, ["role"])


class Migration(migrations.Migration):

    dependencies = [
        ('users', '0015_auto_20220612_0824'),
    ]

    operations = [
        migrations.RunPython(change_user_role, revert_user_role_changes)
    ]

Run Code Online (Sandbox Code Playgroud)

正如你所看到的,这将会出现我上面提到的问题。我使用了枚举示例,但这可以应用于迁移中引用的每个变量。

那么问题又来了:迁移的最佳实践是什么?我们是否应该始终对值进行硬编码而不引用可能更改的外部变量?