Django migration IntegrityError: недопустимый внешний ключ (но данные существуют)

Я постепенно обновляю устаревшее приложение Django с 1.19 -> 2.2 и далее. Для обновления до 2.2 я просто добавил on_delete=models.CASCADE ко всем models.ForeignKey полям, которые не имели ошибки (что мне также пришлось сделать задним числом для существующих миграций, видимо...).

Возможно, связано/не связано с этим, когда я запускаю manage.py migrate, Django выдает следующую ошибку (я сократил имена таблиц/полей для краткости):

django.db.utils.IntegrityError: The row in table 'X' with primary key '3' has an invalid foreign key: X.fieldname_id contains a value '4' that does not have a corresponding value in Y__old.id.

Обратите внимание, в частности, на суффикс __old.id для таблицы db, которая, по ожиданиям Django, должна содержать строку с id 4. При ручной проверке db, таблица Y действительно содержит допустимую строку с id 4! Я предполагаю, что для поддержки миграции Django создает некоторые временные таблицы с суффиксом __old и каким-то образом не может перенести эти данные?

Строка db Y, о которой идет речь, очень проста: столбец char, boolean и число.

Это не идеальное решение, но вы можете вручную удалить строку из базы данных или установить значение внешнего ключа на временное значение, выполнить миграцию, а затем восстановить исходное значение.

Эта проблема вызвана упомянутой ошибкой Django, но если вы получаете ошибку миграции, ваша база данных уже сломана.

Когда вы делаете дамп БД на SQL, вы можете увидеть REFERENCES операторы, которые указывают на таблицы, заканчивающиеся на __old, но эти таблицы на самом деле не существуют:

$> sqlite3 mydb.db .dump | grep '__old'

CREATE TABLE IF NOT EXISTS "company" [...]"account_id" integer NULL REFERENCES "account__old" ("id") [...]

К счастью, БД можно легко исправить, просто удалив __old и сделав дамп в новую базу данных. Это можно автоматизировать с помощью sed:

sqlite3 broken.db .dump | sed 's/REFERENCES "\(.[^"]*\)__old"/REFERENCES "\1"/g' | sqlite3 fixed.db
Вернуться на верх