sql >> Database >  >> RDS >> Mysql

Django ManyToMany door met meerdere databases

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ëren
ADD 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.



  1. Alleen-lezen tabel in mysql

  2. Snel mySQL-klassement met spelersrang (en omringende spelers)

  3. De beste manier om periodiek Oracle-query's uit te voeren

  4. MySql Cursor - Een procedure maken