Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Django ManyToMany mit mehreren Datenbanken durch

Für Django 1.6+ existiert eine Lösung (einschließlich 1.11) für MySQL und sqlite Backends, durch Option ForeignKey. db_constraint =Falsch und explizit Meta.db_table . Wenn der Datenbankname und der Tabellenname in Anführungszeichen stehen durch ' ` ' (für MySQL) oder durch ' " ' (für andere db), z.B. db_table = '"db2"."table2"' ). Dann wird es nicht mehr zitiert und der Punkt ist out of quotes. Gültige Abfragen werden von Django ORM kompiliert. Eine bessere ähnliche Lösung ist db_table = 'db2"."table2' (Das erlaubt nicht nur Joins, sondern ist auch der Cross-DB-Constraint-Migration um ein Problem näher)

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

Abfragesatz:

>>> 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'

Diese Abfrageanalyse wird von allen Datenbank-Backends unterstützt in Django, jedoch müssen andere notwendige Schritte individuell von den Backends besprochen werden. Ich versuche, allgemeiner zu antworten, weil ich einen ähnliche wichtige Frage .

Die Option 'db_constraint' ist für Migrationen notwendig, da Django die Referenzintegritätseinschränkung nicht erstellen kann
ADD foreign key table1(fk_id) REFERENCES db2.table2(id) ,
aber es kann manuell erstellt werden für MySQL.

Eine Frage für bestimmte Backends ist, ob eine andere Datenbank zur Laufzeit mit dem Standard verbunden werden kann und ob ein datenbankübergreifender Fremdschlüssel unterstützt wird. Diese Modelle sind auch beschreibbar. Die indirekt verbundene Datenbank sollte als Legacy-Datenbank mit managed=False verwendet werden (weil nur eine Tabelle django_migrations für die Migrationsverfolgung wird nur in der direkt verbundenen Datenbank erstellt. Diese Tabelle sollte nur Tabellen in derselben Datenbank beschreiben.) Indizes für Fremdschlüssel können jedoch automatisch auf der verwalteten Seite erstellt werden, wenn das Datenbanksystem solche Indizes unterstützt.

Sqlite3 :Es muss zur Laufzeit an eine andere Standard-sqlite3-Datenbank angehängt werden (Antwort SQLite - Wie verbinde ich Tabellen aus verschiedenen Datenbanken ), bestenfalls durch das Signal 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)

Dann braucht es natürlich keinen Datenbankrouter und einen normalen django...ForeignKey kann mit db_constraint=False verwendet werden. Ein Vorteil ist, dass "db_table" nicht notwendig ist, wenn die Tabellennamen zwischen Datenbanken eindeutig sind.

In MySQL Fremdschlüssel zwischen verschiedenen Datenbanken sind einfach. Alle Befehle wie SELECT, INSERT, DELETE unterstützen beliebige Datenbanknamen, ohne sie vorher anzuhängen.

Diese Frage bezog sich auf Legacy-Datenbanken. Ich habe aber auch bei Migrationen einige interessante Ergebnisse.