Er bestaat een oplossing voor Django 1.6+ (inclusief 1.11) voor MySQL en sqlite backends, per optie ForeignKey. db_constraint =Fout
en expliciete Meta.db_table
. Als de databasenaam en tabelnaam aanhalingstekens zijn door ' ` ' (voor MySQL) of door ' " ' (voor andere db), bijv. db_table = '"db2"."table2"'
). Dan wordt het niet meer geciteerd en valt de punt buiten de aanhalingstekens. Geldige zoekopdrachten worden samengesteld door Django ORM. Een betere vergelijkbare oplossing is db_table = 'db2"."table2'
(dat maakt niet alleen joins mogelijk, maar het is ook een kwestie die dichter bij migratie van db-beperkingen ligt)
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
Queryset:
>>> 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'
Die query-parsing wordt ondersteund door alle db-backends in Django, maar andere noodzakelijke stappen moeten afzonderlijk door backends worden besproken. Ik probeer meer in het algemeen te antwoorden omdat ik een vergelijkbare belangrijke vraag .
De optie 'db_constraint' is nodig voor migraties, omdat Django de referentie-integriteitsbeperking niet kan creërenADD foreign key table1(fk_id) REFERENCES db2.table2(id)
,
maar het kan handmatig worden aangemaakt
voor MySQL.
Een vraag voor bepaalde backends is of een andere database tijdens runtime kan worden verbonden met de standaard en of een externe sleutel voor meerdere databases wordt ondersteund. Deze modellen zijn ook beschrijfbaar. De indirect verbonden database moet worden gebruikt als een oude database met managed=False
(omdat slechts één tabel django_migrations
voor migraties wordt tracking alleen gemaakt in de direct gekoppelde database. Deze tabel zou alleen tabellen in dezelfde database moeten beschrijven.) Indexen voor refererende sleutels kunnen echter automatisch worden aangemaakt aan de beheerde kant als het databasesysteem dergelijke indexen ondersteunt.
Sqlite3 :Het moet tijdens runtime aan een andere standaard sqlite3-database worden gekoppeld (antwoord SQLite - Hoe koppel je tabellen uit verschillende databases ), op zijn best door het signaal 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)
Dan heeft het natuurlijk geen databaserouter nodig en een normale django...ForeignKey
kan worden gebruikt met db_constraint=False. Een voordeel is dat "db_table" niet nodig is als de tabelnamen uniek zijn tussen databases.
In MySQL vreemde sleutels tussen verschillende databases zijn gemakkelijk. Alle commando's zoals SELECT, INSERT, DELETE ondersteunen alle databasenamen zonder ze eerder toe te voegen.
Deze vraag ging over legacy databases. Ik heb echter ook enkele interessante resultaten met migraties.