Використовуйте кілька баз даних у Django, використовуючи лише одну таблицю "django_migrations"


11

Для проекту в Django я повинен використовувати дві бази даних: за замовчуванням та віддалену . Я створив routers.pyі все працює добре.

Виникла вимога створити таблицю у віддаленій базі даних, і я створив міграцію, запустив її та django_migrationsстворив таблицю . Я хочу мати лише одну таблицю django_migrationsв базі даних за замовчуванням.

Відповідна частина routers.pyтут:

class MyRouter(object):
     # ...
     def allow_migrate(self, db, app_label, model_name=None, **hints):
         if app_label == 'my_app':
             return db == 'remote'
         return None

Я запускаю міграцію так:

python manage.py migrate my_app --database=remote

Тепер, коли я це роблю:

python manage.py runserver

Я отримую таке попередження:

У вас є 1 неприкладена міграція. Ваш проект може не працювати належним чином, поки ви не застосуєте міграцію для додатків: my_app.
Запустіть "python Manag.py migrate", щоб застосувати їх.

Таблиці для my_appстворюються в remoteбазі даних, а django_migrationsвсередині remoteбази даних міграції позначаються як застосовані.

EDIT:
Як змусити Django використовувати лише одну таблицю django_migrations, але все ж застосувати міграцію до різних баз даних?

Як застосувати міграцію в різних базах даних, щоб не виникало попереджень?


1
для інших програм, які не є "my_app", enable_migrate повертає None. Можливо, ви хочете зробити ще одну перевірку там? З того, що я розумію з вашого маршрутизатора, "my_app" використовує "віддалену" базу даних, а всі інші додатки використовуватимуть базу даних "за замовчуванням"?
Мартін Талеський

@cezar Ви просите майже неможливо. Для того, щоб мати спільну django_migrationsтаблицю, потрібно буде розмежувати рядки з міграціями для defaultта remotedb. Це досить глибоко у внутрішніх джанго. Я навіть ризикну зазначити, що це потребує значного перезапису коду міграції.
Каміль

@KamilNiski дякую, що поділилися своїми думками. Я переформулюю питання.
cezar

Це питання може бути актуальним.
Кевін Крістофер Генрі

Відповіді:


2

Завдяки коментарям до мого запитання я провів деякі дослідження і прийшов до наступних висновків.

Використання декількох баз даних призводить до створення таблиці django_migrationsпри використанні міграцій. Немає можливості записувати міграції лише в одній таблиці django_migrations, як коментар пояснює Каміля Ніскі . Це зрозуміло після прочитання файлу django/db/migrations/recorder.py.

Я проілюструю приклад із проектом fooта додаткомbar всередині проекту. У додатку barє лише одна модель Baz.

Ми створюємо проект:

django-admin startproject foo

Тепер у нас є цей вміст у головному каталозі проектів:

- foo
- manage.py

У мене є звичка групувати всі програми в каталозі проектів:

mkdir foo/bar
python manage.py bar foo/bar

У файлі foo/settings.pyми налаштовуємо налаштування для використання двох різних баз даних для цілей цього прикладуsqlite3 :

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db1.sqlite3'),
    },
    'remote': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
    }
}

Тепер ми виконуємо міграції:

python manage.py migrate --database=default

При цьому виконуються всі міграції, частина --database=defaultє необов'язковою, оскільки якщо Django не вказано, використовується база даних за замовчуванням.

Операції для виконання: 
  Застосовуйте всі міграції: адміністратор, auth, типи вмісту, сеанси
 Запуск міграцій:
  Застосування типів вмісту.0001_initial ... ОК
  Застосування auth.0001_initial ... ОК
  Застосування admin.0001_initial ... ОК
  Застосування admin.0002_logentry_remove_auto_add ... ОК
  Застосування admin.0003_logentry_addgery_flag_choices ... ОК
  Застосування типів вмісту.0002_remove_content_type_name ... ОК
  Застосування auth.0002_alter_permission_name_max_length ... ОК
  Застосування auth.0003_alter_user_email_max_length ... ОК
  Застосування auth.0004_alter_user_username_opts ... ОК
  Застосування auth.0005_alter_user_last_login_null ... ОК
  Застосування auth.0006_require_contenttypes_0002 ... ОК
  Застосування auth.0007_alter_validators_add_error_messages ... ОК
  Застосування auth.0008_alter_user_username_max_length ... ОК
  Застосування auth.0009_alter_user_last_name_max_length ... ОК
  Застосування auth.0010_alter_group_name_max_length ... ОК
  Застосування auth.0011_update_proxy_permissions ... ОК
  Застосування сеансів.0001_initial ... ОК

Django застосував усі міграції до бази даних за замовчуванням:

1 типи вмісту 0001_initial 2019-11-13 16: 51: 04.767382
2 авт 0001_initial 2019-11-13 16: 51: 04.792245
3 адміністратор 0001_initial 2019-11-13 16: 51: 04.827454
4 адмін 0002_logentr 2019-11-13 16: 51: 04.846627
5 адміністратор 0003_logentr 2019-11-13 16: 51: 04.864458
6 типів вмісту 0002_remove_ 2019-11-13 16: 51: 04.892220
7 авт 0002_alter_p 2019-11-13 16: 51: 04.906449
8 авт 0003_alter_u 2019-11-13 16: 51: 04.923902
9 авт 0004_alter_u 2019-11-13 16: 51: 04.941707
10 авт 0005_alter_u 2019-11-13 16: 51: 04.958371
11 авт 0006_потрібно 2019-11-13 16: 51: 04.965527
12 авт 0007_alter_v 2019-11-13 16: 51: 04.981532
13 авт 0008_alter_u 2019-11-13 16: 51: 05.004149
14 авт 0009_alter_u 2019-11-13 16: 51: 05.019705
15 авт 0010_alter_g 2019-11-13 16: 51: 05.037023
16 авт. 0011_update_ 2019-11-13 16: 51: 05.054449
17 сеансів 0001_initial 2019-11-13 16: 51: 05.063868

Тепер ми створюємо модель Baz:

models.py:

from django.db import models

class Baz(models.Model):
    name = models.CharField(max_length=255, unique=True)

зареєструйте додаток barу INSTALLED_APPS( foo/settings.py) та створіть їхграші:

python manage.py makemigrations bar

Перш ніж запустити міграції, які ми створюємо routers.pyвсередині barдодатка:

клас BarRouter (об’єкт):
    def db_for_read (самостійна модель, ** підказки):
        if model._meta.app_label == 'бар':
            повернути "віддалений"
        повернути Ні

    def db_for_write (самостійна модель, ** підказки):
        if model._meta.app_label == 'бар':
            повернути "віддалений"
        повернути Ні

    def enable_relation (self, obj1, obj2, ** підказки):
        повернути Ні

    def enable_migrate (self, db, app_label, model_name = Немає, ** підказки):
        якщо app_label == 'бар':
            return db == 'віддалений'
        якщо db == 'віддалений':
            повернути Неправдиво
        повернути Ні

і зареєструйте його у foo/settings.py:

DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']

Тепер наївним підходом було б запуск міграцій barв remoteбазу даних:

python manage.py migrate bar --database=remote
Операції для виконання: 
  Застосувати всі міграції: bar
 Запуск міграцій:
  Застосування bar.0001_initial ... ОК

Міграції застосовано до remoteбази даних:

1 бар 0001_initial 2019-11-13 17: 32: 39.701784

Коли ми запускаємо:

python manage.py runserver

буде подано таке попередження:

У вас є 1 неприкладена міграція. Ваш проект може не працювати належним чином, поки ви не застосуєте міграцію для додатка: бар.
Запустіть "python Manag.py migrate", щоб застосувати їх.

Здається, все працює добре. Однак це попередження не задовольняє.

Правильним способом було б запустити всі міграції для кожної бази даних, як пропонується у цій відповіді .

Це виглядатиме так:

python manage.py migrate --database=default
python manage.py migrate --database=remote

і після створення міграцій для bar:

python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote

Маршрутизатор подбає про те, щоб таблиця bar_bazбула створена лише в remoteбазі даних, але Django позначить міграції як застосовані в обох базах даних. Також столи для auth, admin, sessionsі т.д. , будуть створені тільки в defaultбазі даних, як зазначено в routers.py. Таблиця django_migrationsв remoteбазі даних матиме записи і про ці міграції.

Це тривале читання, але я сподіваюсь, що він прояснить це питання, на мою думку, не до кінця поясненого питання в офіційній документації .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.