Можно ли воссоздать поле таблицы, которое было случайно удалено из Django Model, не снося все миграции?
Предположим следующую модель:
class Country(models.Model):
name = models.TextField(null=True, blank=True)
continent = models.TextField(null=True, blank=True)
population = models.PositiveIntegerField(null=True, blank=True)
И тогда я:
- Delete the field
population
frommodels.py
. - Create a migration:
python manage.py makemigrations countries_app
- Execute the migration, which marks the field as removed:
python3 manage.py migrate countries_app
Вот файл миграции 0006
, который является последовательностью для последней созданной миграции (0005
):
class Migration(migrations.Migration):
dependencies = [
('countries_app', '0005_auto_20210723_0007'),
]
operations = [
migrations.RemoveField(
model_name='country',
name='population',
),
]
Теперь у меня нет поля population
в моей базе данных, но я понял, что это была ошибка, удалить поле population
из Country
модели.
Пытаясь вернуть все на свои места, я снова определяю поле на модели и отменяю миграцию 0006
, а также удаляю 0006
файл миграции, где было определено удаление поля, а также выполняю python manage.py migrate countries_app
и он говорит nothing to migrate
, что имеет смысл.
$ python3 manage.py migrate countries_app
Operations to perform:
Apply all migrations: countries_app
Running migrations:
Applying countries_app.0006_remove_country_population... OK
$ rm countries_app/migrations/0006_remove_country_population.py
$ python manage.py migrate countries_app
Но когда я проверяю таблицу базы данных, поле population
по-прежнему отсутствует. Я думал, что Django создаст его заново, поскольку я отменил миграцию 0006
и поле снова было определено в моей модели.
Я видел некоторые ответы здесь на SO, в которых говорилось что-то вроде: отменить все миграции (python manage.py migrate countries_app zero
), удалить все файлы миграции, создать начальную миграцию еще раз и затем выполнить миграцию.
Это звучит слишком жестоко для меня. Я бы хотел поручить Django воссоздать поле, которого больше нет. Есть ли какой-нибудь эффективный и более щадящий способ сделать это? Я не настолько продвинут в Django Migrations, поэтому, пожалуйста, потерпите меня. Спасибо.
Конечно, вы можете добавить поле обратно в модель и снова использовать makemigrations
, а затем выполнить миграцию вперед (0006 -> 0007). Это определит столбец обратно в базу данных, но вам придется заново заполнить его действительными данными. Простая миграция просто заполнит его значением по умолчанию.
После некоторого исследования и тестирования, технически, отменяя миграцию 0006
(откатываясь к 0005
), Django воссоздает поле, которое когда-то было удалено. Я провел локальные тесты в другом проекте, и да, это правда.
Почему откат к миграции 0005
не сработал в моем случае, неизвестно. Возможно, я что-то напутал в своем реальном проекте. Поэтому в качестве ответа я заявляю, что откат к предыдущей миграции - это обычно то, что вам нужно в таких случаях.
Но, если все действительно запутано и Django не воссоздает поле, которое когда-то было удалено, а теперь снова появилось в вашей модели, я вижу 2 альтернативы:
Ответ Nigel222. Это будет работать, но все же, принесет дополнительную миграцию, только для воссоздания поля.
Подключитесь к базе данных и вручную создайте поле. Это исправит произошедшую аномалию, и не будет дополнительной миграции только для пересоздания поля, которое должно было вернуться обратно при откате миграции:
ALTER TABLE countries_app_country ADD population INTEGER;