Saltar al contenido

Django ManyToMany a través de múltiples bases de datos

Estate atento porque en esta división vas a encontrar el arreglo que buscas.Esta crónica ha sido aprobado por nuestros especialistas para garantizar la calidad y exactitud de nuestro post.

Solución:

Existe una solución para Django 1.6+ (incluido 1,11) para MySQL y sqlite backends, por opción ForeignKey.db_constraint= Falso y explícito Meta.db_table. Si el nombre de la base de datos y el nombre de la tabla son cotizado por ‘`’ (para MySQL) o por ‘”‘ (para otra base de datos), por ejemplo db_table = '"db2"."table2"'). Entonces no se cotiza más y el punto está fuera de cotización. Las consultas válidas son compiladas por Django ORM. Una mejor solución similar es db_table = 'db2"."table2' (que permite no solo uniones, sino que también es un problema más cercano a la migración de restricción cruzada de db)

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

Conjunto de consultas:

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

Ese análisis de consultas es compatible con todos los backends de db en Django, sin embargo, los backends deben analizar individualmente otros pasos necesarios. Estoy tratando de responder de manera más general porque encontré una pregunta importante similar.

La opción ‘db_constraint’ es necesaria para las migraciones, porque Django no puede crear la restricción de integridad de referencia
ADD foreign key table1(fk_id) REFERENCES db2.table2(id),
pero se puede crear manualmente para MySQL.

Una pregunta para backends particulares es si otra base de datos se puede conectar a la predeterminada en tiempo de ejecución y si una base de datos cruzada es externa key esta apoyado. Estos modelos también se pueden escribir. La base de datos conectada indirectamente debe usarse como una base de datos heredada con managed=False (porque solo una mesa django_migrations para el seguimiento de migraciones se crea solo en la base de datos conectada directamente. Esta tabla debe describir solo las tablas de la misma base de datos.) Índices para extranjeros keys Sin embargo, se puede crear automáticamente en el lado administrado si el sistema de base de datos admite dichos índices.

Sqlite3: Tiene que estar adjunto a otra base de datos sqlite3 predeterminada en tiempo de ejecución (respuesta SQLite – ¿Cómo se unen tablas de diferentes bases de datos), en el mejor de los casos por la señal 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)

Entonces no necesita un enrutador de base de datos, por supuesto y un django...ForeignKey se puede utilizar con db_constraint = False. Una ventaja es que “db_table” no es necesario si los nombres de las tablas son únicos entre las bases de datos.

En MySQL extranjero keys entre diferentes bases de datos es fácil. Todos los comandos como SELECT, INSERT, DELETE admiten cualquier nombre de base de datos sin adjuntarlos previamente.


Esta pregunta trataba sobre bases de datos heredadas. Sin embargo, también tengo algunos resultados interesantes con las migraciones.

Tengo una configuración similar con PostgreSQL. Utilizando search_path para hacer posibles referencias de esquemas cruzados en Django (esquema en postgres = base de datos en mysql). Desafortunadamente, parece que MySQL no tiene tal mecanismo.

Sin embargo, puede probar suerte creando vistas para él. Cree vistas en una base de datos que haga referencia a otras bases de datos, úsela para seleccionar datos. Creo que es la mejor opción, ya que de todos modos desea que sus datos sean de solo lectura.

Sin embargo, no es una solución perfecta, la ejecución de consultas sin procesar puede ser más útil en algunos casos.


UPD: Proporcionar detalles de modo sobre mi configuración con PostgreSQL (según lo solicitado por recompensa más adelante). No pude encontrar nada como search_path en la documentación de MySQL.

Introducción rápida

PostgreSQL tiene esquemas. Son sinónimos de bases de datos MySQL. Entonces, si usted es un usuario de MySQL, reemplace imaginativamente la palabra “esquema” con la palabra “base de datos”. Las solicitudes pueden unir tablas entre esquemas, crear archivos externos keys, etc … Cada usuario (rol) tiene una ruta_de_búsqueda:

Esta variable [search_path] especifica el orden en el que se buscan los esquemas cuando se hace referencia a un objeto (tabla, tipo de datos, función, etc.) mediante un nombre simple sin esquema especificado.

Atención especial a “ningún esquema especificado”, porque eso es exactamente lo que hace Django.

Ejemplo: bases de datos heredadas

Digamos que tenemos esquemas heredados de cupé y, dado que no se nos permite modificarlos, también queremos un nuevo esquema para almacenar la relación NM en él.

  • old1 es el primer esquema heredado, tiene old1_table (que también es el nombre del modelo, por conveniencia)
  • old2 es el segundo esquema heredado, tiene old2_table
  • django_schema es nuevo, almacenará la relación NM requerida

Todo lo que necesitamos hacer es:

alter role django_user set search_path = django_schema, old1, old2;

Eso es todo. Sí, así de simple. Django no tiene nombres de los esquemas (“bases de datos”) especificados en ninguna parte. Django en realidad no tiene idea de lo que está sucediendo, todo lo administra PostgreSQL detrás de escena. Ya que django_schema es el primero en la lista, se crearán nuevas tablas allí. Entonces el siguiente código ->

class Throughtable(models.Model):
    a_id = models.ForeignKey('old1_table', ...)
    b_id = models.ForeignKey('old2_table', ...)

-> resultará en una migración que crea una tabla throughtable que hace referencia old1_table y old2_table.

Problemas: si tiene varias tablas con los mismos nombres, deberá cambiarles el nombre o aún engañar a Django para que use un punto dentro de los nombres de las tablas.

Django tiene la capacidad de trabajar con múltiples bases de datos. Consulte https://docs.djangoproject.com/en/1.11/topics/db/multi-db/.

También puede utilizar consultas SQL sin procesar en Django. Consulte https://docs.djangoproject.com/en/1.11/topics/db/sql/.

Reseñas y puntuaciones del artículo

Recuerda algo, que tienes la opción de añadir un diagnóstico objetivo .

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *