Миграция Django была успешно применена, но база данных не была изменена

Мне нужно использовать дополнительную базу данных SQLite в новом проекте Django. Эта база данных находится в локальной файловой системе, но вне папки Django. Путь к нему указан в .env файле в корневом каталоге проекта Django.

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

Мне удалось интегрировать базу данных в проект Django, и я не вижу никаких ошибок ни на одном этапе. Я могу извлекать данные из базы данных через оболочку Django. Однако, когда я пытаюсь применить миграцию, ничего не происходит: база данных не изменяется, но Django не выдает мне никакой ошибки (на самом деле это говорит о том, что миграция была применена).

Вот что я сделал:

  1. создал приложение-архиватор в Django
  2. в этом приложении создан файл routers.py со следующим кодом:
class ArchiverDbRouter:

    def db_for_read(self, model, **hints):
        if model._meta.app_label in ['archiver']:
            return 'archiver'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label in ['archiver']:
            return 'archiver'
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label in ['archiver']:
            return db == 'archiver'
        return None

  1. настроен settings.py на использование двух баз данных. Идея состоит в том, чтобы сохранить базу данных по умолчанию для всего Django, а затем базу данных "archiver" для приложения "archiver".
import os
from pathlib import Path
from dotenv import load_dotenv

load_dotenv()
USER_DIR = Path(os.getenv('USER_DIR', './user'))

(...)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    },
    'archiver': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': USER_DIR / 'data/app.db',
    }
}

DATABASE_ROUTERS = ['archiver.routers.ArchiverDbRouter']
  1. сгенерировал свои модели с помощью команды inspectdb:
python manage.py inspectdb --database archiver > tempmodels.py

Затем отредактировал эти модели и сохранил их в archiver/models.py. Я удалил свойства managed = False во всех моделях.

  1. инициализировал базу данных
python manage.py migrate

При этом создается файл базы данных "по умолчанию".

  1. сгенерировал миграции для архиватора
python manage.py makemigrations archiver

Создан файл переноса 0001_initial.py.

  1. применил эту миграцию с флагом --fake
python manage.py migrate archiver 0001 --fake

Я вижу соответствующую миграцию, сохраненную в таблице django_migrations.

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

>>> q = State(account="test", name="test", value="test")
>>> q.save()

Затем я вижу, что новая строка (с тремя "тестовыми" значениями) присутствует в таблице "состояния" базы данных m "archiver" (с использованием стороннего инструмента HeidiSQL). Я также вижу, что дата изменения файла базы данных была обновлена.

  1. внес некоторые изменения в мой models.py, удалив поле, которое никогда не использовалось в модели Post.

  2. снова сгенерировал миграции

python manage.py makemigrations archiver

Файл переноса создан:

from django.db import migrations

class Migration(migrations.Migration):

    dependencies = [
        ('archiver', '0001_initial'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='post',
            name='note',
        ),
    ]
  1. применен новый перенос
python manage.py migrate archiver

Это дает мне результат:

Operations to perform:
  Apply all migrations: archiver
Running migrations:
  Applying archiver.0002_remove_post_note... OK

Ошибки нет. Я вижу соответствующую миграцию, сохраненную в таблице django_migrations.

ОДНАКО, когда я просматриваю базу данных архиватора (снова используя HeidiSQL), поле "примечание" по-прежнему присутствует. Кроме того, "дата изменения" для файла базы данных не изменилась.

Что я упускаю?

Итак, при дальнейшем тестировании я заметил, что:

Запуск python manage.py sqlmigrate archiver 0002 --database=archiver показывает правильный результат SQL:

BEGIN;
--
-- Remove field note from post
--
ALTER TABLE "posts" DROP COLUMN "note";
COMMIT;

Принимая во внимание, что если я не использую флаг --database, то SQL-код в основном пуст:

$ python manage.py sqlmigrate archiver 0002
BEGIN;
--
-- Remove field note from post
--
-- (no-op)
COMMIT;

По-видимому, Django пытается применить миграцию к базе данных по умолчанию, что приводит к появлению фрагмента пустого SQL-кода, который, очевидно, не имеет никакого эффекта (но и не вызывает ошибки). Заметить это непросто.

Таким образом, похоже, что маршрутизатор не учитывается при использовании команды migrate, и решение состоит в том, чтобы просто указать его в целевой базе данных (если не используется база данных по умолчанию):

python manage.py migrate archiver --database=archiver
Вернуться на верх