Bases de datos múltiples

Esta guía describe el soporte de Django para interactuar con múltiples bases de datos. La mayoría del resto de la documentación de Django asume que estás interactuando con una sola base de datos. Si deseas interactuar con múltiples bases de datos, necesitarás realizar algunos pasos adicionales.

Ver también

Consultar Soporte para múltiples bases de datos para obtener información sobre la prueba con múltiples bases de datos.

Definir las bases de datos

El primer paso para utilizar más de una base de datos con Django es informar a Django sobre los servidores de bases de datos que vas a usar. Esto se hace utilizando el parámetro DATABASES. Este parámetro mapea alias de bases de datos, que son una forma de referirse a una base de datos específica en todo Django, a un diccionario de configuración para esa conexión específica. Los valores en los diccionarios internos se describen completamente en la documentación de DATABASES.

Las bases de datos pueden tener cualquier alias que elijas. Sin embargo, el alias default tiene significado especial. Django utiliza la base de datos con el alias default cuando no se ha seleccionado otra.

El siguiente es un ejemplo de snippet en settings.py que define dos bases de datos – una base de datos PostgreSQL por defecto y una base de datos MySQL llamada users:

DATABASES = {
    "default": {
        "NAME": "app_data",
        "ENGINE": "django.db.backends.postgresql",
        "USER": "postgres_user",
        "PASSWORD": "s3krit",
    },
    "users": {
        "NAME": "user_data",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "priv4te",
    },
}

Si el concepto de una base de datos por defecto no tiene sentido en el contexto de tu proyecto, debes tener cuidado de especificar siempre la base de datos que deseas usar. Django requiere que se defina una entrada de base de datos por defecto, pero la lista de parámetros puede dejarse vacía si no se utilizará. Para hacer esto, debes configurar DATABASE_ROUTERS para todos los modelos de tus aplicaciones, incluyendo aquellos en cualquier aplicación contribuyente y de terceros que estés utilizando, para que ninguna consulta sea enviada a la base de datos por defecto. El siguiente es un ejemplo de snippet settings.py que define dos bases de datos no por defecto, con la entrada por defecto dejada vacía intencionalmente:

DATABASES = {
    "default": {},
    "users": {
        "NAME": "user_data",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "superS3cret",
    },
    "customers": {
        "NAME": "customer_data",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_cust",
        "PASSWORD": "veryPriv@ate",
    },
}

Si intentas acceder a una base de datos que no has definido en tu DATABASES configuración, Django levantará un excepción django.utils.connection.ConnectionDoesNotExist.

Sincronizando tus bases de datos

El comando administrativo migrate opera sobre una base de datos a la vez. Por defecto, opera sobre la base de datos por defecto, pero proporcionando la opción --database puedes indicarle que sincronice una base de datos diferente. Para sincronizar todos los modelos en todas las bases de datos del ejemplo anterior, deberías llamar a:

$ ./manage.py migrate
$ ./manage.py migrate --database=users

Si no deseas que cada aplicación se sincronice con una base de datos particular, puedes definir un router de base de datos que implemente una política que restrinja la disponibilidad de modelos particulares.

Si, como en el segundo ejemplo anterior, has dejado vacía la base de datos por defecto, debes proporcionar el nombre de la base de datos cada vez que ejecutes migrate. Omitir el nombre de la base de datos levantaría un error. Para el segundo ejemplo:

$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=customers

Usando otros comandos administrativos

La mayoría de los demás comandos django-admin que interactúan con la base de datos operan de la misma manera que migrate – solo operan sobre una base de datos a la vez, utilizando --database para controlar la base de datos utilizada.

Una excepción a esta regla es el comando administrativo makemigrations. Valida la historia de migraciones en las bases de datos para detectar problemas con los archivos de migración existentes (que podrían haber sido causados por editarlos) antes de crear nuevas migraciones. Por defecto, solo verifica la base de datos por defecto, pero consulta el método allow_migrate() de cualquier router si alguno está instalado.

Ruteo de bases de datos automático

La traducción de los textos es la siguiente:

No tienes que hacer nada para activar el esquema de enrutamiento por defecto – está proporcionado “de serie” en cada proyecto Django. Sin embargo, si deseas implementar comportamientos más interesantes de asignación de bases de datos, puedes definir y instalar tus propios routers de base de datos.

Routers de base de datos

Un Router de base de datos es una clase que proporciona hasta cuatro métodos:

db_for_read(model, **hints)

Sugerir la base de datos que se debe utilizar para operaciones de lectura de objetos del tipo model.

Si una operación de base de datos puede proporcionar alguna información adicional que pueda ayudar a seleccionar una base de datos, se proporcionará en el diccionario hints. Los detalles sobre las sugerencias válidas se proporcionan a continuación.

Devuelve None si no hay sugerencia.

db_for_write(model, **hints)

Sugerir la base de datos que se debe utilizar para escrituras de objetos del tipo Model.

Si una operación de base de datos puede proporcionar alguna información adicional que pueda ayudar a seleccionar una base de datos, se proporcionará en el diccionario hints. Los detalles sobre las sugerencias válidas se proporcionan a continuación.

Devuelve None si no hay sugerencia.

allow_relation(obj1, obj2, **hints)

Devolver True si una relación entre obj1 y obj2 debe permitirse, False si la relación debe rechazarse o None si el router no tiene opinión. Esta es una operación puramente de validación, utilizada por las claves foráneas y las operaciones muchos a muchos para determinar si se debe permitir una relación entre dos objetos.

Si ningún router tiene opinión (es decir, todos los routers devuelven None), solo se permiten relaciones dentro de la misma base de datos.

allow_migrate(db, app_label, model_name=None, **hints)

Determine si la operación de migración está permitida para ejecutarse en la base de datos con alias db. Devuelve True si la operación debe ejecutarse, False si no debería ejecutarse, o None si el router no tiene opinión.

La argumento posicional app_label es el etiqueta del aplicación que se está migrando.

model_name se establece por la mayoría de las operaciones de migración al valor de model._meta.model_name (la versión lowercaser de la modelo __name__) del modelo que se está migrando. Su valor es None para las operaciones RunPython y RunSQL a menos que proporcionen el valor utilizando indicaciones.

Las indicaciones se utilizan por ciertas operaciones para comunicar información adicional al router.

Cuando model_name está establecido, indicaciones normalmente contiene la clase del modelo bajo la clave 'model'. Tenga en cuenta que puede ser un modelo histórico <historical-models> y, por lo tanto, no tiene atributos personalizados, métodos ni administradores. Solo debe confiar en _meta.

Esta método también se puede utilizar para determinar la disponibilidad de un modelo en una base de datos dada.

makemigrations siempre crea migraciones para cambios de modelos, pero si allow_migrate() devuelve False, cualquier operación de migración para el model_name se saltará silenciosamente cuando se ejecuta migrate en la db. Cambiar el comportamiento de allow_migrate() para modelos que ya tienen migraciones puede resultar en claves foráneas rotas, tablas adicionales o faltantes. Cuando makemigrations verifica la historia de migración, ignora las bases de datos donde no se permite que ninguna aplicación migre.

Un router no tiene que proporcionar todos estos métodos – puede omitir uno o más de ellos. Si se omite uno de los métodos, Django ignorará ese router cuando se realice la verificación relevante.

Indicaciones

Las indicaciones recibidas por el router de base de datos se pueden utilizar para decidir qué base de datos debe recibir una solicitud dada.

En este momento, la única pista que se proporcionará es instance, un objeto de instancia relacionado con la operación de lectura o escritura en curso. Esto podría ser la instancia que está siendo guardada, o podría ser una instancia que se está agregando en una relación muchos-a-muchos. En algunos casos, no se proporcionará ninguna pista de instancia. El router verifica la existencia de una pista de instancia y determina si esa pista debe usarse para alterar el comportamiento de la ruta.

Uso de routers

Los routers de bases son instalados utilizando la configuración DATABASE_ROUTERS. Esta configuración define una lista de nombres de clase, cada uno que especifica un router que debe usarse por el router base (django.db.router).

El router base se utiliza para las operaciones de bases de datos de Django para asignar el uso de la base de datos. Cada vez que una consulta necesita saber qué base de datos utilizar, llama al router base, proporcionando un modelo y una pista (si está disponible). El router base intenta cada clase de router en turno hasta que uno devuelve una sugerencia de base de datos. Si ningún router devuelve una sugerencia, el router base intenta la base de datos actual instance._state.db de la instancia de pista. Si no se proporcionó ninguna instancia de pista o instance._state.db es None, el router base asignará la base de datos default.

Un ejemplo

Ejemplo a efectos exclusivos!

Este ejemplo está destinado a demostrar cómo se puede alterar el uso de bases de datos utilizando la infraestructura del router. Intencionalmente ignora algunas complejas cuestiones para demostrar cómo se utilizan los routers.

Este ejemplo no funcionará si alguna de las modelos en myapp contienen relaciones con modelos fuera de la base de datos other. Las relaciones entre bases de datos cruzadas <no_cross_database_relations> introducen problemas de integridad referencial que Django no puede manejar actualmente.

La configuración primaria/replica (referred a como maestro/esclavo por algunas bases de datos) descrita también es defectuosa – no proporciona ninguna solución para manejar el retraso de replicación (es decir, inconsistencias en las consultas introducidas debido al tiempo necesario para que una escritura se propague a los replicas). También no considera la interacción de transacciones con la estrategia de utilización de bases de datos.

Entonces - ¿qué significa esto en la práctica? Vamos a considerar otra configuración de muestra. Esta tendrá varias bases de datos: una para la aplicación auth y todas las otras aplicaciones utilizando un conjunto primario/replica con dos replicas de lectura. Aquí están los ajustes que especifican estas bases de datos:

DATABASES = {
    "default": {},
    "auth_db": {
        "NAME": "auth_db_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "swordfish",
    },
    "primary": {
        "NAME": "primary_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "spam",
    },
    "replica1": {
        "NAME": "replica1_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "eggs",
    },
    "replica2": {
        "NAME": "replica2_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "bacon",
    },
}

Ahora necesitamos manejar la ruta. Primero queremos un router que sepa enviar consultas para las aplicaciones auth y contenttypes a auth_db (los modelos de auth están vinculados a ContentType, por lo que deben estar almacenados en la misma base de datos):

class AuthRouter:
    """
    A router to control all database operations on models in the
    auth and contenttypes applications.
    """

    route_app_labels = {"auth", "contenttypes"}

    def db_for_read(self, model, **hints):
        """
        Attempts to read auth and contenttypes models go to auth_db.
        """
        if model._meta.app_label in self.route_app_labels:
            return "auth_db"
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth and contenttypes models go to auth_db.
        """
        if model._meta.app_label in self.route_app_labels:
            return "auth_db"
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the auth or contenttypes apps is
        involved.
        """
        if (
            obj1._meta.app_label in self.route_app_labels
            or obj2._meta.app_label in self.route_app_labels
        ):
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth and contenttypes apps only appear in the
        'auth_db' database.
        """
        if app_label in self.route_app_labels:
            return db == "auth_db"
        return None

Y también queremos un router que envíe todas las otras aplicaciones a la configuración principal/replica y elija al azar una réplica para leer desde:

import random


class PrimaryReplicaRouter:
    def db_for_read(self, model, **hints):
        """
        Reads go to a randomly-chosen replica.
        """
        return random.choice(["replica1", "replica2"])

    def db_for_write(self, model, **hints):
        """
        Writes always go to primary.
        """
        return "primary"

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the primary/replica pool.
        """
        db_set = {"primary", "replica1", "replica2"}
        if obj1._state.db in db_set and obj2._state.db in db_set:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True

Finalmente, en el archivo de configuración, agregamos lo siguiente (sustituyendo path.to. con el camino real Python al módulo(s) donde los routers están definidos):

DATABASE_ROUTERS = ["path.to.AuthRouter", "path.to.PrimaryReplicaRouter"]

El orden en que se procesan los routers es significativo. Los routers se consultarán en el orden en que estén listados en la configuración DATABASE_ROUTERS. En este ejemplo, AuthRouter se procesa antes de PrimaryReplicaRouter, y como resultado, las decisiones concernientes a los modelos en auth se procesan antes de cualquier otra decisión. Si la configuración DATABASE_ROUTERS listara los dos routers en el otro orden, PrimaryReplicaRouter.allow_migrate() se procesaría primero. La naturaleza catch-all de la implementación del PrimaryReplicaRouter significaría que todos los modelos estarían disponibles en todas las bases de datos.

Con esta configuración instalada y todas las bases de datos migradas según Sincronizando tus bases de datos, ejecutemos algún código Django:

>>> # This retrieval will be performed on the 'auth_db' database
>>> fred = User.objects.get(username="fred")
>>> fred.first_name = "Frederick"

>>> # This save will also be directed to 'auth_db'
>>> fred.save()

>>> # These retrieval will be randomly allocated to a replica database
>>> dna = Person.objects.get(name="Douglas Adams")

>>> # A new object has no database allocation when created
>>> mh = Book(title="Mostly Harmless")

>>> # This assignment will consult the router, and set mh onto
>>> # the same database as the author object
>>> mh.author = dna

>>> # This save will force the 'mh' instance onto the primary database...
>>> mh.save()

>>> # ... but if we re-retrieve the object, it will come back on a replica
>>> mh = Book.objects.get(title="Mostly Harmless")

Este ejemplo definió un router para manejar la interacción con modelos de la aplicación auth, y otros routers para manejar la interacción con todas las otras aplicaciones. Si dejaste tu base de datos predeterminada vacía y no quieres definir una ruta de base de datos catch-all para manejar todas las aplicaciones que no se especifican, tus routers deben manejar los nombres de todas las aplicaciones en INSTALLED_APPS antes de migrar. Consulta Behavior of contrib apps para obtener información sobre contrib apps que deben estar juntas en una base de datos.

Seleccionando manualmente una base de datos

Django también proporciona una API que permite mantener el control completo sobre el uso de bases de datos en tu código. Una asignación manual de base de datos tendrá prioridad sobre la asignada por un router.

Seleccionar manualmente una base de datos para un QuerySet

Puedes seleccionar la base de datos para un QuerySet en cualquier punto de la cadena del QuerySet. Llama a using() en el QuerySet para obtener otro QuerySet que utiliza la base de datos especificada.

Usando() toma un argumento único: el alias de la base de datos en la que deseas ejecutar la consulta. Por ejemplo:

>>> # This will run on the 'default' database.
>>> Author.objects.all()

>>> # So will this.
>>> Author.objects.using("default")

>>> # This will run on the 'other' database.
>>> Author.objects.using("other")

Seleccionar una base de datos para save()

Utiliza la palabra clave using para Model.save() para especificar a qué base de datos se deben guardar los datos.

Por ejemplo, para guardar un objeto en la base de datos legacy_users, utilizarías esto:

>>> my_object.save(using="legacy_users")

Si no especificas using, el método save() guardará en la base de datos predeterminada asignada por los routers.

Mover un objeto de una base de datos a otra

Si has guardado una instancia en una base de datos, podría ser tentador utilizar save(using=...) como forma de migrar la instancia a una nueva base de datos. Sin embargo, si no tomas las medidas adecuadas, esto podría tener algunas consecuencias inesperadas.

Considera el siguiente ejemplo:

>>> p = Person(name="Fred")
>>> p.save(using="first")  # (statement 1)
>>> p.save(using="second")  # (statement 2)

En la sentencia 1, un nuevo objeto Person se guarda en la base de datos ``first””. En este momento, ``p”” no tiene una clave primaria, por lo que Django emite una sentencia SQL ``INSERT””. Esto crea una clave primaria y Django asigna esa clave a ``p””.

Cuando ocurre el guardado en la sentencia 2, ``p”” ya tiene un valor de clave primaria y Django intentará utilizar ese valor de clave primaria en la nueva base de datos. Si el valor de clave primaria no está en uso en la base de datos ``second””, entonces no tendrás ningún problema – el objeto se copiará a la nueva base de datos.

Sin embargo, si la clave primaria de p ya está en uso en la base de datos second, el objeto existente en la base de datos second se sobrescribirá cuando se guarde p.

Puedes evitar esto de dos maneras. Primero, puedes borrar la clave primaria del instante. Si un objeto no tiene una clave primaria, Django lo tratará como un nuevo objeto, evitando cualquier pérdida de datos en la base de datos second:

>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.pk = None  # Clear the primary key.
>>> p.save(using="second")  # Write a completely new object.

La segunda opción es utilizar la opción force_insert para save() para asegurarse de que Django haga un SQL INSERT.

>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.save(using="second", force_insert=True)

Esto garantizará que la persona llamada Fred tenga la misma clave primaria en ambas bases de datos. Si esa clave primaria ya está en uso cuando intentes guardar en la base de datos second, se levantará un error.

Seleccionar una base de datos para eliminar

Por defecto, una llamada a eliminar un objeto existente se ejecutará en la misma base de datos que se utilizó para recuperar el objeto por primera vez:

>>> u = User.objects.using("legacy_users").get(username="fred")
>>> u.delete()  # will delete from the `legacy_users` database

Para especificar la base de datos desde la cual se eliminará un modelo, pasa un argumento using al método Model.delete(). Este argumento funciona exactamente igual que el argumento using en save().

Por ejemplo, si estás migrando a un usuario de la base de datos legacy_users a la base de datos new_users, podrías utilizar estos comandos:

>>> user_obj.save(using="new_users")
>>> user_obj.delete(using="legacy_users")

Usar administradores con múltiples bases de datos

Utiliza el método db_manager() en los administradores para darles acceso a una base de datos no por defecto.

Por ejemplo, si tienes un método personalizado del administrador que interactúa con la base de datos – User.objects.create_user(). Dado que create_user() es un método del administrador y no un método de QuerySet, no puedes hacer User.objects.using('new_users').create_user(). (El método create_user() solo está disponible en User.objects, el administrador, y no en objetos QuerySet derivados del administrador.) La solución es utilizar db_manager(), de la siguiente manera:

User.objects.db_manager("new_users").create_user(...)

db_manager() devuelve una copia del administrador vinculado a la base de datos que especificas.

Usando get_queryset() con múltiples bases de datos

Si estás sobreescribiendo get_queryset() en tu administrador, asegúrate de llamar al método en el padre (utilizando super()) o manejar adecuadamente la propiedad _db del administrador (una cadena que contiene el nombre de la base de datos a utilizar).

Por ejemplo, si quieres devolver una clase personalizada QuerySet desde el método get_queryset, podrías hacer esto:

class MyManager(models.Manager):
    def get_queryset(self):
        qs = CustomQuerySet(self.model)
        if self._db is not None:
            qs = qs.using(self._db)
        return qs

Mostrar múltiples bases de datos en la interfaz administrativa de Django

Django no tiene soporte explícito para múltiples bases de datos. Si deseas proporcionar una interfaz administrativa para un modelo en una base de datos diferente a la especificada por tu cadena de rutas, necesitarás escribir clases personalizadas :class:`~django.contrib.admin.ModelAdmin` que dirijan al administrador a utilizar una base de datos específica para el contenido.

Los objetos ModelAdmin tienen los siguientes métodos que requieren personalización para soportar múltiples bases de datos:

class MultiDBModelAdmin(admin.ModelAdmin):
    # A handy constant for the name of the alternate database.
    using = "other"

    def save_model(self, request, obj, form, change):
        # Tell Django to save objects to the 'other' database.
        obj.save(using=self.using)

    def delete_model(self, request, obj):
        # Tell Django to delete objects from the 'other' database
        obj.delete(using=self.using)

    def get_queryset(self, request):
        # Tell Django to look for objects on the 'other' database.
        return super().get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super().formfield_for_foreignkey(
            db_field, request, using=self.using, **kwargs
        )

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super().formfield_for_manytomany(
            db_field, request, using=self.using, **kwargs
        )

La implementación proporcionada aquí implementa una estrategia de múltiples bases de datos donde todos los objetos de un tipo determinado se almacenan en una base de datos específica (por ejemplo, todos los objetos User están en la base de datos other). Si tu uso de múltiples bases de datos es más complejo, tu administrador ModelAdmin necesitará reflejar esa estrategia.

Los objetos :class:`~django.contrib.admin.InlineModelAdmin` se pueden manejar de manera similar. Requieren tres métodos personalizados:

class MultiDBTabularInline(admin.TabularInline):
    using = "other"

    def get_queryset(self, request):
        # Tell Django to look for inline objects on the 'other' database.
        return super().get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super().formfield_for_foreignkey(
            db_field, request, using=self.using, **kwargs
        )

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super().formfield_for_manytomany(
            db_field, request, using=self.using, **kwargs
        )

Una vez que hayas escrito tus definiciones de administración de modelos, pueden registrarse con cualquier instancia Admin:

from django.contrib import admin
from myapp.models import Author, Book, Publisher

# Import our custom ModelAdmin and TabularInline from where they're defined.
from myproject.admin import MultiDBModelAdmin, MultiDBTabularInline


# Specialize the multi-db admin objects for use with specific models.
class BookInline(MultiDBTabularInline):
    model = Book


class PublisherAdmin(MultiDBModelAdmin):
    inlines = [BookInline]


admin.site.register(Author, MultiDBModelAdmin)
admin.site.register(Publisher, PublisherAdmin)

othersite = admin.AdminSite("othersite")
othersite.register(Publisher, MultiDBModelAdmin)

Este ejemplo configura dos sitios de administración. En el primer sitio, se exponen los objetos Author y Publisher; los objetos Publisher tienen una pestaña en línea tabular que muestra libros publicados por ese editor. El segundo sitio expone solo a los editores, sin las pestañas en línea.

Uso de cursor bruto con múltiples bases de datos

Si estás utilizando más de una base de datos puedes usar django.db.connections para obtener la conexión (y cursor) de una base de datos específica. django.db.connections es un objeto similar a un diccionario que te permite recuperar una conexión específica usando su alias:

from django.db import connections

with connections["my_db_alias"].cursor() as cursor:
    ...

Limitaciones de múltiples bases de datos

Relaciones entre bases de datos cruzadas

Django no proporciona actualmente ninguna ayuda para relaciones de clave foránea o muchos a muchos que se extiendan por varias bases de datos. Si has utilizado un router para particionar modelos en diferentes bases de datos, cualquier relación de clave foránea y muchos a muchos definida por esos modelos debe ser interna a una sola base de datos.

Esto es debido a la integridad referencial. Para mantener una relación entre dos objetos, Django necesita saber que la clave primaria del objeto relacionado es válida. Si la clave primaria se almacena en una base de datos separada, no es posible evaluar fácilmente la validez de una clave primaria.

Si estás utilizando Postgres, SQLite, Oracle o MySQL con InnoDB, esto se aplica a nivel de integridad de la base de datos – las restricciones de clave principal en el nivel de la base de datos impiden la creación de relaciones que no pueden ser validadas.

Sin embargo, si estás utilizando MySQL con tablas MyISAM, no hay integridad referencial impuesta; como resultado, puedes “simular” claves foráneas entre bases de datos. Sin embargo, esta configuración no está oficialmente soportada por Django.

Behavior of contrib apps

Varios contrib apps incluyen modelos, y algunos apps dependen de otros. Dado que las relaciones entre bases de datos cruzadas son imposibles, esto crea algunas restricciones sobre cómo puedes dividir estos modelos a través de bases de datos:

  • cada uno de contenttypes.ContentType, sessions.Session y sites.Site puede almacenarse en cualquier base de datos, siempre que haya un router adecuado.

  • Los modelos authUser, Group y Permission — están vinculados entre sí y vinculados a ContentType, por lo que deben estar almacenados en la misma base de datos que ContentType.

  • admin depende de auth, por lo que sus modelos deben estar en la misma base de datos que auth.

  • flatpages y redirects dependen de sites, por lo que sus modelos deben estar en la misma base de datos que sites.

Además, algunos objetos se crean automáticamente justo después de migrate crea una tabla para almacenarlos en una base de datos:

  • un sitio predeterminado Site,

  • un ContentType para cada modelo (incluyendo aquellos que no están almacenados en esa base de datos),

  • las Permissions para cada modelo (incluyendo aquellos que no están almacenados en esa base de datos).

Los textos traducidos son:

Advertencia

Si estás sincronizando tipos de contenido con más de una base de datos, ten en cuenta que sus claves primarias pueden no coincidir entre bases de datos. Esto puede resultar en corrupción o pérdida de datos.