Graças aos comentários sobre minha pergunta, fiz algumas pesquisas e descobri as seguintes conclusões.
O uso de vários bancos de dados resulta na criação de uma tabela django_migrationsquando as migrações são usadas. Não há opção para registrar as migrações em apenas uma tabela django_migrations, como explica o comentário de Kamil Niski . Isso fica claro após a leitura do arquivo django/db/migrations/recorder.py.
Ilustrarei um exemplo com um projeto fooe um aplicativo bardentro do projeto. O aplicativo barpossui apenas um modelo Baz.
Criamos o projeto:
django-admin startproject foo
Agora, temos este conteúdo dentro do diretório principal do projeto:
- foo
- manage.py
Eu tenho o hábito de agrupar todos os aplicativos dentro do diretório do projeto:
mkdir foo/bar
python manage.py bar foo/bar
No arquivo foo/settings.py, ajustamos as configurações para usar dois bancos de dados diferentes. Para os fins deste exemplo, usamos 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'),
}
}
Agora, executamos as migrações:
python manage.py migrate --database=default
Isso executa todas as migrações, a parte --database=defaulté opcional, porque se não for especificado, o Django usa o banco de dados padrão.
Operações a serem executadas:
aplique todas as migrações: admin, auth, contenttypes, sessions
Executando migrações:
Aplicando contenttypes.0001_initial ... OK
Aplicando auth.0001_initial ... OK
Aplicando admin.0001_initial ... OK
Aplicando admin.0002_logentry_remove_auto_add ... OK
Aplicando admin.0003_logentry_add_action_flag_choices ... OK
Aplicando contenttypes.0002_remove_content_type_name ... OK
Aplicando auth.0002_alter_permission_name_max_length ... OK
Aplicando auth.0003_alter_user_email_max_length ... OK
Aplicando auth.0004_alter_user_username_opts ... OK
Aplicando auth.0005_alter_user_last_login_null ... OK
Aplicando auth.0006_require_contenttypes_0002 ... OK
Aplicando auth.0007_alter_validators_add_error_messages ... OK
Aplicando auth.0008_alter_user_username_max_length ... OK
Aplicando auth.0009_alter_user_last_name_max_length ... OK
Aplicando auth.0010_alter_group_name_max_length ... OK
Aplicando auth.0011_update_proxy_permissions ... OK
Aplicando sessions.0001_initial ... OK
O Django aplicou todas as migrações ao banco de dados padrão:
1 contenttypes 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 tipos de conteúdo 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 sessões 0001_initial 2019-11-13 16: 51: 05.063868
Agora criamos o modelo Baz:
models.py:
from django.db import models
class Baz(models.Model):
name = models.CharField(max_length=255, unique=True)
registre o aplicativo barem INSTALLED_APPS( foo/settings.py) e crie as migrações:
python manage.py makemigrations bar
Antes de executar as migrações que criamos routers.pydentro do baraplicativo:
classe BarRouter (objeto):
def db_for_read (self, model, ** dicas):
if model._meta.app_label == 'bar':
retornar 'remoto'
retornar Nenhum
def db_for_write (self, model, ** dicas):
if model._meta.app_label == 'bar':
retornar 'remoto'
retornar Nenhum
def allow_relation (auto, obj1, obj2, ** dicas):
retornar Nenhum
def allow_migrate (self, db, app_label, model_name = None, ** dicas):
se app_label == 'bar':
return db == 'remoto'
se db == 'remoto':
retorna falso
retornar Nenhum
e registre-o em foo/settings.py:
DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']
Agora, a abordagem ingênua seria executar as migrações para baro remotebanco de dados:
python manage.py migrate bar --database=remote
Operações a serem executadas:
Aplicar todas as migrações: bar
Executando migrações:
Aplicando bar.0001_initial ... OK
As migrações foram aplicadas ao remotebanco de dados:
1 bar 0001_initial 2019-11-13 17: 32: 39.701784
Quando corremos:
python manage.py runserver
o seguinte aviso será gerado:
Você tem 1 migração (s) não aplicada (s). Seu projeto pode não funcionar corretamente até você aplicar as migrações para o (s) aplicativo (s): bar.
Execute 'python manage.py migrate' para aplicá-los.
Tudo parece funcionar bem embora. No entanto, não é satisfatório receber esse aviso.
A maneira correta seria executar todas as migrações para cada banco de dados, conforme sugerido nesta resposta .
Seria assim:
python manage.py migrate --database=default
python manage.py migrate --database=remote
e depois de criar as migrações para bar:
python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote
O roteador cuidará para que a tabela bar_bazseja criada apenas no remotebanco de dados, mas o Django marcará as migrações como aplicadas nos dois bancos de dados. Também as mesas para auth, admin, sessions, etc. será criado apenas no defaultbanco de dados, conforme especificado no routers.py. A tabela django_migrationsno remotebanco de dados também terá registros para essas migrações.
É uma leitura longa, mas espero que ajude a esclarecer isso, na minha opinião, questão não completamente explicada na documentação oficial .