Dank der Kommentare zu meiner Frage habe ich einige Nachforschungen angestellt und die folgenden Ergebnisse erzielt.
Die Verwendung mehrerer Datenbanken führt zur Erstellung einer Tabelle, django_migrations
wenn Migrationen verwendet werden. Es gibt keine Möglichkeit, die Migrationen in nur einer Tabelle aufzuzeichnen django_migrations
, wie der Kommentar von Kamil Niski erklärt. Dies ist nach dem Lesen der Datei klar django/db/migrations/recorder.py
.
Ich werde ein Beispiel mit einem Projekt foo
und einer App bar
innerhalb des Projekts veranschaulichen . Die App bar
hat nur ein Modell Baz
.
Wir erstellen das Projekt:
django-admin startproject foo
Jetzt haben wir diese Inhalte im Hauptprojektverzeichnis:
- foo
- manage.py
Ich habe die Angewohnheit, alle Apps im Projektverzeichnis zu gruppieren:
mkdir foo/bar
python manage.py bar foo/bar
In der Datei foo/settings.py
passen wir die Einstellungen an, um zwei verschiedene Datenbanken zu verwenden. Für die Zwecke dieses Beispiels verwenden wir 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'),
}
}
Jetzt führen wir die Migrationen durch:
python manage.py migrate --database=default
Dadurch werden alle Migrationen ausgeführt. Der Teil --database=default
ist optional, da Django die Standarddatenbank verwendet, wenn nichts angegeben ist.
Durchzuführende Vorgänge : Alle Migrationen anwenden: admin, auth, contenttypes, session
Ausführen von Migrationen:
Anwenden von Inhaltstypen.0001_initial ... OK
Auth.0001_initial anwenden ... OK
Anwenden von admin.0001_initial ... OK
Anwenden von admin.0002_logentry_remove_auto_add ... OK
Anwenden von admin.0003_logentry_add_action_flag_choices ... OK
Anwenden von Inhaltstypen.0002_remove_content_type_name ... OK
Anwenden von auth.0002_alter_permission_name_max_length ... OK
Anwenden von auth.0003_alter_user_email_max_length ... OK
Anwenden von auth.0004_alter_user_username_opts ... OK
Anwenden von auth.0005_alter_user_last_login_null ... OK
Anwenden von auth.0006_require_contenttypes_0002 ... OK
Anwenden von auth.0007_alter_validators_add_error_messages ... OK
Anwenden von auth.0008_alter_user_username_max_length ... OK
Anwenden von auth.0009_alter_user_last_name_max_length ... OK
Anwenden von auth.0010_alter_group_name_max_length ... OK
Anwenden von auth.0011_update_proxy_permissions ... OK
Sessions anwenden.0001_initial ... OK
Django hat alle Migrationen auf die Standarddatenbank angewendet:
1 Inhaltstypen 0001_initial 2019-11-13 16: 51: 04.767382
2 auth 0001_initial 2019-11-13 16: 51: 04.792245
3 admin 0001_initial 2019-11-13 16: 51: 04.827454
4 admin 0002_logentr 2019-11-13 16: 51: 04.846627
5 admin 0003_logentr 2019-11-13 16: 51: 04.864458
6 Inhaltstypen 0002_remove_ 2019-11-13 16: 51: 04.892220
7 auth 0002_alter_p 2019-11-13 16: 51: 04.906449
8 auth 0003_alter_u 2019-11-13 16: 51: 04.923902
9 auth 0004_alter_u 2019-11-13 16: 51: 04.941707
10 auth 0005_alter_u 2019-11-13 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 2019-11-13 16: 51: 05.019705
15 auth 0010_alter_g 2019-11-13 16: 51: 05.037023
16 auth 0011_update_ 2019-11-13 16: 51: 05.054449
17 Sitzungen 0001_initial 2019-11-13 16: 51: 05.063868
Jetzt erstellen wir das Modell Baz
:
models.py
::
from django.db import models
class Baz(models.Model):
name = models.CharField(max_length=255, unique=True)
Registrieren Sie die App bar
in INSTALLED_APPS
( foo/settings.py
) und erstellen Sie die Migrationen:
python manage.py makemigrations bar
Bevor wir die Migrationen ausführen, die wir routers.py
in der bar
App erstellen :
Klasse BarRouter (Objekt):
def db_for_read (Selbst, Modell, ** Hinweise):
if model._meta.app_label == 'bar':
'Remote' zurückgeben
Rückgabe Keine
def db_for_write (Selbst, Modell, ** Hinweise):
if model._meta.app_label == 'bar':
'Remote' zurückgeben
Rückgabe Keine
def allow_relation (self, obj1, obj2, ** Hinweise):
Rückgabe Keine
def allow_migrate (self, db, app_label, model_name = Keine, ** Hinweise):
if app_label == 'bar':
return db == 'remote'
if db == 'remote':
falsch zurückgeben
Rückgabe Keine
und registrieren Sie es in foo/settings.py
:
DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']
Nun wäre der naive Ansatz, die Migrationen für bar
in die remote
Datenbank auszuführen :
python manage.py migrate bar --database=remote
Durchzuführende Vorgänge: Alle Migrationen anwenden: Leiste
Ausführen von Migrationen:
Anwenden von bar.0001_initial ... OK
Die Migrationen wurden auf die remote
Datenbank angewendet :
1 bar 0001_initial 2019-11-13 17: 32: 39.701784
Wenn wir rennen:
python manage.py runserver
Die folgende Warnung wird ausgegeben:
Sie haben 1 nicht angewendete Migration (en). Ihr Projekt funktioniert möglicherweise erst ordnungsgemäß, wenn Sie die Migrationen für App (s): bar anwenden.
Führen Sie 'python manage.py migrate' aus, um sie anzuwenden.
Alles scheint gut zu funktionieren. Es ist jedoch nicht zufriedenstellend, diese Warnung zu haben.
Der richtige Weg wäre, alle Migrationen für jede Datenbank auszuführen, wie in dieser Antwort vorgeschlagen .
Es würde so aussehen:
python manage.py migrate --database=default
python manage.py migrate --database=remote
und nach dem Erstellen der Migrationen für bar
:
python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote
Der Router sorgt dafür, dass die Tabelle bar_baz
nur in der remote
Datenbank erstellt wird, aber Django markiert die Migrationen als in beiden Datenbanken angewendet. Auch die Tabellen für auth
, admin
, sessions
etc. werden nur in der erstellt werden default
Datenbank, wie angegeben in routers.py
. Die Tabelle django_migrations
in der remote
Datenbank enthält auch Datensätze für diese Migrationen.
Es ist eine lange Lektüre, aber ich hoffe, sie wirft ein Licht auf dieses meiner Meinung nach nicht gründlich erläuterte Problem in der offiziellen Dokumentation .
django_migrations
Tabelle zu haben , muss zwischen Zeilen mit Migrationen fürdefault
undremote
db unterschieden werden. Dies ist ziemlich tief in den Django-Interna. Ich würde sogar das Risiko eingehen, zu behaupten, dass der Migrationscode grundlegend neu geschrieben werden müsste.