sql >> Databasteknik >  >> RDS >> Mysql

Django ManyToMany genom med flera databaser

Det finns en lösning för Django 1.6+ (inklusive 1.11) för MySQL och sqlite backends, genom alternativ ForeignKey. db_constraint =False och explicit Meta.db_table . Om databasnamnet och tabellnamnet är citerade av ' ` ' (för MySQL) eller av ' " ' (för annan db), t.ex. db_table = '"db2"."table2"' ). Då citeras det inte mer och pricken är ur citat. Giltiga frågor sammanställs av Django ORM. En bättre liknande lösning är db_table = 'db2"."table2' (som inte bara tillåter anslutningar utan det är också av en fråga närmare migrering av db-begränsningar)

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

Frågeuppsättning:

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

Den frågetolkningen stöds av alla db-backends i Django måste dock andra nödvändiga steg diskuteras individuellt av backends. Jag försöker svara mer allmänt eftersom jag hittade en liknande viktig fråga .

Alternativet 'db_constraint' är nödvändigt för migrering, eftersom Django inte kan skapa referensintegritetsbegränsningen
ADD foreign key table1(fk_id) REFERENCES db2.table2(id) ,
men den kan skapas manuellt för MySQL.

En fråga för särskilda backends är om en annan databas kan anslutas till standarden vid körning och om en främmande nyckel för flera databaser stöds. Dessa modeller är också skrivbara. Den indirekt anslutna databasen ska användas som en äldre databas med managed=False (eftersom bara en tabell django_migrations för migrationer skapas spårning endast i den direktanslutna databasen. Denna tabell ska endast beskriva tabeller i samma databas.) Index för främmande nycklar kan dock skapas automatiskt på den hanterade sidan om databassystemet stöder sådana index.

Sqlite3 :Den måste kopplas till en annan standard sqlite3-databas vid körning (svar SQLite - Hur sammanfogar du tabeller från olika databaser ), i bästa fall genom signalen 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)

Då behöver den inte en databasrouter förstås och en vanlig django...ForeignKey kan användas med db_constraint=False. En fördel är att "db_table" inte behövs om tabellnamnen är unika mellan databaser.

I MySQL främmande nycklar mellan olika databaser är lätta. Alla kommandon som SELECT, INSERT, DELETE stöder alla databasnamn utan att bifoga dem tidigare.

Den här frågan handlade om äldre databaser. Jag har dock några intressanta resultat även med migrationer.



  1. If-uttalande inom Where-klausulen

  2. Introduktion till Väntestatistik

  3. Förbättring av en funktion som UPSERT baseras på en inmatningsmatris

  4. Kerberos för SQLyog av MariaDB Connector/C