Как добавить новое поле в модель после пользовательской миграции, которая получает доступ к модели перед новым полем?
У меня есть пользовательский файл миграции, который создает запись в таблице user. Первоначальный рабочий проект имеет такие миграции:
1. 001_initial.py # creates model with some fields
2. 002_custom_user_data.py # adds data in "user" due some middle requirement after some time.
Теперь я хочу добавить еще один столбец в эту таблицу как "config_data". Для этого я выполнил следующие шаги:
1. python manage.py makemigrations <app-name> # creates one more migration file` 003_add_config_data_field.py
2. python manage.py migrate # raise an error
Команда migrate вызывает ошибку ниже.
Applying my_user.001_initial.py... OK
Applying my_user.002_custom_user_data.py ...Traceback (most recent call last):
File "/home/myhome/.local/share/virtualenvs/myproject/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedColumn: column my_user.config_data does not exist
LINE 1: ..., "my_user"."address",
Это происходит потому, что миграция 002 пытается получить доступ к таблице my_user до того, как миграция add field(003) будет перенесена в таблицу, что вызывает ошибку UndefinedColumn config_data error.
Есть идеи, как можно решить эту проблему, поскольку эти миграции должны работать как для свежей БД, так и для производственной БД, в которой до 002 мигрировали ранее.
Ниже приведена миграция для 002_custom_user_data.py
# Generated by Django 3.2.2
from django.db import migrations
from myapp.models import MyUser
def create_user(apps, schema_editor):
user = MyUser.objects.get_or_create(id=123)
user.address = 'demo'
user.save()
def delete_user(apps, schema_editor):
MyUser.objects.filter(id=123).delete()
class Migration(migrations.Migration):
dependencies = [
('my_user', '001_initial'),
]
Спасибо.
Вам следует импортировать модель historical, а не вашу текущую модель. Django отслеживает, как выглядела модель до того, как вы запустили миграцию, вы можете получить доступ к такой модели с помощью метода apps.get_model(…)
[Django-doc]:
from django.db import migrations
# No import from myapp.models!
def create_user(apps, schema_editor):
MyUser = apps.get_model('my_user', 'MyUser')
user = MyUser.objects.get_or_create(id=123)
user.address = 'demo'
user.save()
def delete_user(apps, schema_editor):
MyUser = apps.get_model('my_user', 'MyUser')
MyUser.objects.filter(id=123).delete()
class Migration(migrations.Migration):
dependencies = [
('my_user', '001_initial'),
]
Модель MyUser
, которую мы здесь используем, сама по себе не будет иметь все поля, которые вы определили в models.py
, и поля сами по себе не будут иметь тот же тип. Таким образом, вы можете работать с моделью так, как она была в тот момент времени, и таким образом определять миграции данных . Записи будут обновлены позже, если вы, например, создадите дополнительное поле.