Ссылки на внешние переменные в миграциях данных Django
Для моделей мы используем apps.get_model()
, чтобы убедиться, что при миграции будет использоваться правильная версия модели (та, которая была на момент определения миграции).
Но как быть с "обычными" переменными (не моделями), импортированными из базы данных?
Предположим, я хочу просто изменить значение поля с помощью переменной, которую я определил где-то в кодовой базе. Например, я хочу превратить всех обычных пользователей в администраторов. Я сохранил роли пользователей в перечислении (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)
]
Но теперь есть проблемы.
- Если когда-нибудь в будущем я удалю переменную
UserRoles
(потому что изменю реализацию), это нарушит миграции. Поэтому я не смогу повторно запустить миграции локально, чтобы создать базу данных с нуля. - Если я модифицирую переменную (например, изменю порядок значений перечисления), это приведет к неожиданным последствиям при выполнении обратной операции над существующей базой данных.
Я использовал пример с перечислением, но это можно применить к любой переменной, на которую ссылаются внутри миграций.
Какая лучшая практика для миграций? Должны ли мы всегда жестко кодировать значения, не обращаясь к внешним переменным, которые могут измениться?