Istnieje rozwiązanie dla Django 1.6+ (w tym 1.11) dla MySQL i sqlite backendy, według opcji ForeignKey. db_ograniczenie =Fałsz
i jawny Meta.db_table
. Jeśli nazwa bazy danych i nazwa tabeli są zacytowane przez ' ` ' (dla MySQL) lub przez ' " ' (dla innej bazy danych), np. db_table = '"db2"."table2"'
). Wtedy nie jest już cytowany, a kropka nie jest cytowana. Poprawne zapytania są kompilowane przez Django ORM. Lepszym podobnym rozwiązaniem jest db_table = 'db2"."table2'
(co pozwala nie tylko na połączenia, ale jest również o jeden problem bliższe migracji ograniczeń między bazami danych)
db2_name = settings.DATABASES['db2']['NAME']
class Table1(models.Model):
fk = models.ForeignKey('Table2', on_delete=models.DO_NOTHING, db_constraint=False)
class Table2(models.Model):
name = models.CharField(max_length=10)
....
class Meta:
db_table = '`%s`.`table2`' % db2_name # for MySQL
# db_table = '"db2"."table2"' # for all other backends
managed = False
Zestaw zapytań:
>>> qs = Table2.objects.all()
>>> str(qs.query)
'SELECT "DB2"."table2"."id" FROM DB2"."table2"'
>>> qs = Table1.objects.filter(fk__name='B')
>>> str(qs.query)
SELECT "app_table1"."id"
FROM "app_table1"
INNER JOIN "db2"."app_table2" ON ( "app_table1"."fk_id" = "db2"."app_table2"."id" )
WHERE "db2"."app_table2"."b" = 'B'
Przetwarzanie zapytania jest obsługiwane przez wszystkie backendy bazy danych w Django, jednak inne niezbędne kroki muszą być omówione indywidualnie przez backendy. Próbuję odpowiedzieć bardziej ogólnie, ponieważ znalazłem podobne ważne pytanie .
Opcja 'db_constraint' jest konieczna w przypadku migracji, ponieważ Django nie może utworzyć ograniczenia integralności referencjiADD foreign key table1(fk_id) REFERENCES db2.table2(id)
,
ale można utworzyć ręcznie
dla MySQL.
Pytanie dla konkretnych backendów brzmi, czy inna baza danych może być podłączona do domyślnej w czasie wykonywania i czy obsługiwany jest klucz obcy między bazami danych. Modele te można również pisać. Pośrednio podłączona baza danych powinna być używana jako starsza baza danych z managed=False
(ponieważ tylko jedna tabela django_migrations
śledzenie migracji jest tworzone tylko w bezpośrednio połączonej bazie danych. Ta tabela powinna opisywać tylko tabele w tej samej bazie danych.) Indeksy kluczy obcych mogą być jednak tworzone automatycznie po stronie zarządzanej, jeśli system bazy danych obsługuje takie indeksy.
Sqlite3 :Musi być dołączony do innej domyślnej bazy danych sqlite3 w czasie wykonywania (odpowiedź SQLite - Jak połączyć tabele z różnych baz danych ), najlepiej przez sygnał connection_created :
from django.db.backends.signals import connection_created
def signal_handler(sender, connection, **kwargs):
if connection.alias == 'default' and connection.vendor == 'sqlite':
cur = connection.cursor()
cur.execute("attach '%s' as db2" % db2_name)
# cur.execute("PRAGMA foreign_keys = ON") # optional
connection_created.connect(signal_handler)
Wtedy oczywiście nie jest potrzebny router bazy danych i zwykły django...ForeignKey
może być używany z db_constraint=False. Zaletą jest to, że "db_table" nie jest konieczne, jeśli nazwy tabel są unikalne w różnych bazach danych.
W MySQL klucze obce między różnymi bazami danych są łatwe. Wszystkie polecenia, takie jak SELECT, INSERT, DELETE, obsługują dowolne nazwy baz danych bez ich wcześniejszego dołączania.
To pytanie dotyczyło starszych baz danych. Mam jednak kilka interesujących wyników również z migracjami.