Dzięki komentarzom do mojego pytania przeprowadziłem badania i opracowałem następujące ustalenia.
Korzystanie z wielu baz danych powoduje utworzenie tabeli django_migrations
podczas korzystania z migracji. Jak wyjaśnia django_migrations
komentarz Kamila Niski'ego, nie ma opcji rejestrowania migracji tylko w jednej tabeli . Wyraźnie widać to po odczytaniu pliku django/db/migrations/recorder.py
.
Zilustruję przykład z projektem foo
i aplikacją bar
wewnątrz projektu. Aplikacja bar
ma tylko jeden model Baz
.
Tworzymy projekt:
django-admin startproject foo
Teraz mamy te treści w głównym katalogu projektu:
- foo
- manage.py
Mam zwyczaj grupować wszystkie aplikacje w katalogu projektu:
mkdir foo/bar
python manage.py bar foo/bar
W pliku foo/settings.py
dostosowujemy ustawienia, aby używać dwóch różnych baz danych, do celów tego przykładu używamy 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'),
}
}
Teraz uruchamiamy migracje:
python manage.py migrate --database=default
To uruchamia wszystkie migracje, część --database=default
jest opcjonalna, ponieważ jeśli nie zostanie określony, Django używa domyślnej bazy danych.
Operacje do wykonania:
Zastosuj wszystkie migracje: admin, auth, typy zawartości, sesje
Uruchamianie migracji:
Stosuję typy treści 0001_inicjalne ... OK
Zastosowanie auth.0001_initial ... OK
Aplikuję admin.0001_initial ... OK
Stosowanie admin.0002_logentry_remove_auto_add ... OK
Stosowanie admin.0003_logentry_add_action_flag_choices ... OK
Stosowanie typów treści 0002_usunąć_nazwa_typu treści ... OK
Stosuję auth.0002_alter_permission_name_max_length ... OK
Stosowanie auth.0003_alter_user_email_max_length ... OK
Stosowanie auth.0004_alter_user_username_opts ... OK
Stosowanie auth.0005_alter_user_last_login_null ... OK
Zastosowanie auth.0006_require_contenttypes_0002 ... OK
Stosowanie wiadomości auth.0007_alter_validators_add_error_messages ... OK
Stosowanie auth.0008_nazwa_użytkownika_nazwa_użytkownika_maksymalna_długość ... OK
Stosowanie auth.0009_alter_user_last_name_max_length ... OK
Stosowanie auth.0010_alter_group_name_max_length ... OK
Stosowanie auth.0011_update_proxy_permissions ... OK
Stosowanie sesji 0001_inicjalne ... OK
Django zastosował wszystkie migracje do domyślnej bazy danych:
1 typy treści 0001_initial 13.11.2016 16: 51: 04.767382
2 auth 0001_initial 13.11.2010 16: 51: 04.792245
3 admin 0001_initial 13.11.2010 16: 51: 04.827454
4 admin 0002_logentr 13.11.2010 16: 51: 04.846627
5 admin 0003_logentr 13.11.2019 16: 51: 04.864458
6 typów treści 0002_remove_ 13.11.2016 16: 51: 04.892220
7 auth 0002_alter_p 2019-11-13 16: 51: 04.906449
8 auth 0003_alter_u 13.11.2010 16: 51: 04.923902
9 auth 0004_alter_u 2019-11-13 16: 51: 04.941707
10 auth 0005_alter_u 13.11.2010 16: 51: 04.958371
11 auth 0006_require 2019-11-13 16: 51: 04.965527
12 auth 0007_alter_v 2019-11-13 16: 51: 04.981532
13 auth 0008_alter_u 2019-11-13 16: 51: 05.004149
14 auth 0009_alter_u 13.11.2010 16: 51: 05.019705
15 auth 0010_alter_g 13.11.2010 16: 51: 05.037023
16 auth 0011_update_ 13.11.2010 16: 51: 05.054449
17 sesji 0001_initial 13.11.2016 16: 51: 05.063868
Teraz tworzymy model Baz
:
models.py
:
from django.db import models
class Baz(models.Model):
name = models.CharField(max_length=255, unique=True)
zarejestruj aplikację bar
w INSTALLED_APPS
( foo/settings.py
) i utwórz migracje:
python manage.py makemigrations bar
Przed uruchomieniem migracji tworzymy routers.py
w bar
aplikacji:
klasa BarRouter (obiekt):
def db_for_read (self, model, ** wskazówki):
if model._meta.app_label == 'bar':
zwróć „zdalne”
zwrot Brak
def db_for_write (self, model, ** wskazówki):
if model._meta.app_label == 'bar':
zwróć „zdalne”
zwrot Brak
def allow_relation (self, obj1, obj2, ** wskazówki):
zwrot Brak
def allow_migrate (self, db, app_label, model_name = None, ** wskazówki):
if app_label == 'bar':
return db == 'remote'
jeśli db == 'remote':
zwrócić False
zwrot Brak
i zarejestruj go w foo/settings.py
:
DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']
Teraz naiwnym podejściem byłoby uruchomienie migracji bar
do remote
bazy danych:
python manage.py migrate bar --database=remote
Operacje do wykonania:
Zastosuj wszystkie migracje: pasek
Uruchamianie migracji:
Stosowanie paska bar.0001_initial ... OK
Migracje zostały zastosowane do remote
bazy danych:
1 takt 0001_inicjalny 13.11.2019 17: 32: 39.701784
Kiedy biegniemy:
python manage.py runserver
zostanie wygenerowane następujące ostrzeżenie:
Masz 1 niestosowanych migracji. Twój projekt może nie działać poprawnie, dopóki nie zastosujesz migracji aplikacji: bar.
Uruchom „python manage.py migrate”, aby je zastosować.
Wszystko wydaje się jednak działać dobrze. To ostrzeżenie nie jest jednak satysfakcjonujące.
Właściwym sposobem byłoby uruchomienie wszystkich migracji dla każdej bazy danych, jak sugerowano w tej odpowiedzi .
Wyglądałoby to tak:
python manage.py migrate --database=default
python manage.py migrate --database=remote
i po utworzeniu migracji dla bar
:
python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote
Router upewni się, że tabela bar_baz
jest tworzona tylko w remote
bazie danych, ale Django oznaczy migracje jako zastosowane w obu bazach danych. Także stoły do auth
, admin
, sessions
, itd. Zostaną utworzone tylko w default
bazie danych, jak określono w routers.py
. Tabela django_migrations
w remote
bazie danych będzie również zawierać rekordy dla tych migracji.
To długie czytanie, ale mam nadzieję, że rzuci nieco światła na to, moim zdaniem, nie do końca wyjaśnione zagadnienie w oficjalnej dokumentacji .