Cómo utilizar múltiples bases de datos en Django
Nuevo en Django 1.2: consulte las notas de la versión
La mayoría del resto de la documentación asume el uso de una única base de datos. Este artículo analiza principalmente cómo utilizar múltiples bases de datos en Django. El uso de varias bases de datos requiere algunos pasos adicionales.
Definición de su base de datos
El primer paso al utilizar múltiples bases de datos es configurar los servicios de base de datos que se utilizarán a través de la base de datos. Esta configuración se utiliza para asignar alias de bases de datos y un diccionario de configuraciones de conexión específicas, que es la forma en que Django siempre ha definido las bases de datos. Consulte la documentación de la base de datos para conocer la configuración interna del diccionario.
La base de datos puede utilizar cualquier alias, pero el valor predeterminado tiene un significado especial. Cuando no se selecciona ninguna otra base de datos, Django siempre usa el alias de base de datos predeterminado. Por lo tanto, si no define una base de datos denominada predeterminada, debe tener cuidado de especificar la base de datos que desea usar antes de usarla.
El siguiente es un fragmento de código de settings.py que define dos bases de datos. Defina una base de datos PostgreSQL predeterminada y una base de datos denominada usuarios:
DATABASES = { 'default':{'NAME':'app_data','ENGINE':'django.db.backends.PostgreSQL_ psycopg 2 ', 'USUARIO': 'postgres_user', 'CONTRASEÑA': 's3krit' }, 'usuarios': { 'NOMBRE': 'user_data', 'MOTOR': 'django db MySQL', 'USUARIO': 'mysql_user. ', 'PASSWORD': 'priv4te' } }
Django lanzará un Django si intentas acceder a una base de datos que no está definida en la configuración de la base de datos. db.utils.connectiondonoenotexistException.
Sincronice su base de datos
Los comandos de administración de Syncdb solo pueden operar en una base de datos a la vez. De forma predeterminada, ejecuta la base de datos predeterminada. Pero usando el parámetro -database, puede permitir que syncdb sincronice diferentes bases de datos. Entonces, en nuestro ejemplo, para sincronizar todos los modelos para todas las bases de datos, usaríamos el siguiente comando:
$ ./manage.py syncdb
$ ./manage .py sync db -database=users
Si no sincroniza todos los programas con la misma base de datos, puede definir una ruta de base de datos para implementar estrategias de control específicas para un modelo específico.
Si desea un control detallado sobre la sincronización, también hay una manera de modificar la salida de sqlall y ejecutar manualmente el comando en la base de datos. Los comandos son los siguientes:
$ ./manage.py sqlall sales |. /manage.py dbshell
Usar otros comandos de administración
Otros comandos de django-admin.py para operar bases de datos son similares a syncdb. Solo operan en una base de datos a la vez y usan -database para controlar qué base de datos se utiliza.
Enrutamiento automático de bases de datos
La forma más sencilla de utilizar varias bases de datos es configurar un esquema de enrutamiento de bases de datos. El esquema de enrutamiento predeterminado garantiza que los objetos estén "cerca" de su base de datos original (es decir, que los objetos se guarden nuevamente en su base de datos de origen). El esquema de enrutamiento predeterminado también garantiza que si no se especifica ninguna base de datos, todas las consultas actuarán en la base de datos predeterminada.
No tienes que hacer nada para habilitar el esquema de enrutamiento predeterminado ya que está "listo para usar". Sin embargo, si desea realizar algún comportamiento de asignación de base de datos más interesante, puede definir e instalar sus propias rutas de base de datos.
Enrutamiento de bases de datos
El enrutamiento de bases de datos es una clase con hasta cuatro métodos:
db_for_read (modelo, * *pista)
Se recomienda utilizar una base de datos para escribir objetos modelo.
Si la operación de la base de datos puede proporcionar información adicional útil para seleccionar una base de datos, se puede proporcionar a través de un diccionario rápido. Consulte a continuación para obtener más detalles.
No se devuelve ninguno si no hay sugerencias.
db_for_write(model, * *hint)
Se recomienda utilizar una base de datos para leer los objetos del modelo.
Si la operación de la base de datos puede proporcionar información adicional útil para seleccionar una base de datos, se puede proporcionar a través de un diccionario rápido. Consulte a continuación para obtener más detalles.
No se devuelve ninguno si no hay sugerencias.
allow_relation(obj1, obj2, * *Prompt)
Devuelve Verdadero cuando la relación entre obj1 y obj2 está permitida, Falso cuando no está permitida y Ninguno cuando no hay opinión. Esta es una operación de verificación pura, utilizada en operaciones de clave externa y de muchos a muchos para verificar si la relación entre dos objetos está permitida.
allow_syncdb(base de datos, modelo)
Determina si el modelo se puede sincronizar con una base de datos con db como alias. Si puede devolver Verdadero, si no puede devolver Falso o si no hay opinión, no se devolverá. Este método se utiliza para determinar si un modelo para una base de datos determinada está disponible.
Una ruta no tiene que proporcionar todos estos métodos; se pueden omitir uno o más de ellos. Si omite uno de estos métodos, Django omitirá la ruta correspondiente al realizar comprobaciones relacionadas.
Parámetro de solicitud
El parámetro "prompt" recibido por la ruta de la base de datos se puede utilizar para decidir qué base de datos debe recibir una solicitud determinada.
Actualmente, el único parámetro de solicitud que se puede proporcionar es una instancia, es decir, una instancia de un objeto relacionado con operaciones de lectura y escritura. Puede ser una instancia de un objeto guardado o una instancia agregada en una relación de muchos a muchos. En algunos casos, es posible que no haya ninguna instancia de objeto que proporcionar. La ruta verificará si la instancia de sugerencia existe y decidirá si cambiar el comportamiento de enrutamiento en consecuencia.
Usar enrutamiento
Utilice la configuración DATABASE_ROUTERS para instalar el enrutamiento de la base de datos. Esta configuración define una lista de nombres de clases, cada clase define una ruta para la ruta principal (django.db.router).
Django utiliza la ruta principal para distribuir las operaciones de la base de datos. Cuando una consulta quiere saber qué base de datos usar, proporciona un modelo y una pista (si corresponde) y llama a la ruta principal.
Django probará cada ruta en orden,
hasta que encuentre una sugerencia de ruta adecuada. Si no se encuentran sugerencias de ruta, se probará el _state.db actual del indicador de instancia. Si no se proporciona ninguna sugerencia de ruta, o la instancia no tiene un estado de base de datos actual, la ruta principal asigna una base de datos predeterminada.
Un ejemplo
¡Solo con fines ilustrativos!
Este ejemplo sólo pretende mostrar cómo el enrutamiento cambia el uso de la base de datos. Este ejemplo omite intencionalmente algunas complejidades para mostrar mejor cómo funciona el enrutamiento.
Este ejemplo no funcionará si algún modelo en myapp contiene una relación con un modelo en otra base de datos. Consulte los problemas de integridad referencial de Django cubiertos en la sección Relaciones entre bases de datos.
La configuración maestro/esclavo de este ejemplo también tiene fallas: no maneja retrasos de replicación (por ejemplo, inconsistencias en las consultas causadas por la transferencia de operaciones de escritura a la base de datos esclava que requiere mucho tiempo), ni tiene en cuenta la Interacción de la estrategia de uso de la base de datos.
Entonces, ¿para qué sirve este ejemplo? Este ejemplo es solo para demostrar que myapp existe en otras bases de datos y que todos los demás modelos tienen una relación maestro/esclavo y existen en las bases de datos maestra, esclava1 y esclava2.
Este ejemplo utiliza dos rutas:
Clase MyAppRouter(objeto): "Una ruta que controla todas las operaciones de base de datos del modelo en la aplicación myapp" " def db_for_read(self, model, * * sugerencias): " aplicación myapp La operación del modelo apunta a 'otro'" if model. _ meta . app _ label == ' myapp ': return ' other ' return none def db _ for _ write (self, model, * * sugerencias): "model en la aplicación myapp La operación apunta a 'otro' if model._meta.app_label == 'myapp':return 'other' return none def enable_relation(self, obj1, obj2, **hints): "si contiene el modelo myapp, entonces permita todas las relaciones "si obj1._meta.app_label = 'myapp' u obj2._meta.app_label = 'myapp': devuelve verdadero devuelve ninguno def enable_syncdb(se lf, db, model): "Asegúrese de que la aplicación myapp solo exista en ' otra' base de datos" if db == 'otro': modelo de retorno. aplicación_etiqueta == 'miaplicación' modelo elif. 'miaplicación': retorno falso retorno Ninguno clase masterslaverouter (objeto): "Ruta con definición simple maestro/esclavo" def db_for_read (self, modelo, * * mensaje): "Todas las operaciones de lectura se dirigen a una base de datos esclava aleatoria" devuelve aleatorio. Choice (['slave1', 'slave2']) def db_for_write(self, model, * *hint): "Todas las escrituras se dirigen a la base de datos maestra" return 'master' def Allow_relation(self, obj1, obj2, **hint ): "Permitir cualquier relación entre dos objetos en el grupo de bases de datos" db_list = ('maestro', esclavo1', 'esclavo 2') si obj 1. _ estado. db_list y db en obj 2. _ estado. db en db_list: Devuelve Verdadero Devuelve ninguno def enable_syncdb(self, db, model): "Mostrar modelos en todas las bases de datos" Devuelve Verdadero.
Luego agregue lo siguiente a su archivo de configuración (reemplace ruta.to con la ruta al modelo que define las rutas):
DATABASE _ ROUTERS =[' ruta a . approuter ',' path.to.MasterSlaveRouter']
El orden de las rutas es muy importante en esta configuración porque las consultas se realizan en el orden en esta configuración. En el ejemplo anterior, MyAppRouter viene antes que MasterSlaveRouter, por lo que los modelos en myapp tienen prioridad sobre otros modelos. Si se cambia el orden de dos rutas en la configuración DATABASE_ROUTERS, MasterSlaveRouter.allow_syncdb() tendrá prioridad. Debido a que MasterSlaveRouter lo incluye todo, todos los modelos pueden usar todas las bases de datos.
Una vez completada la configuración, ejecutemos algo de código:
& gt& gt& gt#Obtener datos de la base de datos "credenciales"> & gt& gtfred = User.objects.get(nombre de usuario = 'Fred')>& gt& gtFred. first_name = 'Frederic' & gt& gt& gt# Guardar en la base de datos 'credenciales' > & gt& gtFred save()& gt;& gt& gt# De la base de datos Obtener datos aleatoriamente en > & gt& gtdna = Person.objects.get(name= 'Douglas Adams')& gt& gt& gt#No se asigna ninguna base de datos al crear un nuevo objeto > & gt& gtmh = Libro(title= 'Mostly Harmless' )& gt& gt& gt# Esto La asignación enviará una solicitud a la ruta y configurará la base de datos de mh para que sea la misma que el objeto de autor >;& gt& gt# Base de datos > & gt& gtmh.author = dna & gt& gt& gt# Esto forzará que la instancia "mh " use la ruta principal base de datos...>>>MH.save()>>>#...pero si obtenemos el objeto nuevamente, lo obtendremos de la base de datos>>>mh = Book.objects.get (title= 'Mostly Harmless') p>
Selección manual de la base de datos
Django también proporciona una API que le permite controlar completamente el uso de la base de datos a través del código. Las asignaciones de bases de datos definidas manualmente tienen prioridad sobre el enrutamiento.
Seleccione manualmente la base de datos para el conjunto de consultas.
Puede seleccionar una base de datos para un conjunto de consultas en cualquier punto de la "cadena" del conjunto de consultas. Obtenemos otro conjunto de consultas usando la base de datos especificada llamando a usando() en el conjunto de consultas.
El uso de () requiere un parámetro: el alias de la base de datos en la que se ejecutará la consulta. Por ejemplo:
& gt& gt& gt#Esto se ejecutará en la base de datos "predeterminada". >& gt& gtauthor . all()>>& gt#Esto también se ejecutará en la base de datos "predeterminada". & gt& gt& gtAuthor.objects.using('predeterminado '). all()>>>#Esto se ejecutará en la "otra" base de datos. & gt& gt& gtAuthor.objects.using('otro'). All()
Seleccione la base de datos para guardar()
Cuando use Model.save(), agregue la palabra clave using para especificar en qué base de datos guardar.
Por ejemplo, para guardar un objeto en la base de datos Legacy_users, haría lo siguiente:
& gt& gt& gtmy_object.save(using='legacy_users ')
Si el uso no está definido, el método save() guardará los datos en la base de datos predeterminada de acuerdo con la asignación de ruta.
Mover objetos de una base de datos a otra.
Cuando guardas un objeto en una base de datos, puedes usar guardar (usando =...) para mover el objeto a otra base de datos. Sin embargo, si no utiliza los métodos adecuados, puede haber consecuencias no deseadas.
Supongamos el siguiente ejemplo:
& gt& gt& gtp = Persona(nombre = 'Fred')& gt;& gt& gtP.save(using='first') #(No . Una oración)> & gt& gtP.save(using='segundo') #(Segundo lugar)
Primero, guarde un nuevo objeto Persona en la primera base de datos. En este punto, P no tiene clave principal, por lo que Django ejecuta una instrucción INSERT SQL.
Esto creará una clave principal y la asignará a la p.
En la segunda oración, debido a que P ya tiene una clave primaria, Django intentará usar esta clave primaria en la nueva base de datos al guardar el objeto. Si esta clave primaria no se utiliza en la segunda base de datos, no habrá ningún problema y los objetos se copiarán a la nueva base de datos.
Sin embargo, si la clave primaria de p ya se usa en la segunda base de datos, entonces los objetos existentes que usan esta clave primaria en la segunda base de datos serán sobrescritos por p.
Existen dos formas de evitar la situación anterior. Primero, puede borrar la clave principal de la instancia. Si un objeto no tiene una clave principal, Django lo tratará como un objeto nuevo y lo guardará en la segunda base de datos sin pérdida de datos:
& gt& gt& gtp = Persona(nombre = ' Fred ' )> ;& gt& gtp . save(using = ' first ')>& gt& gtP.pk = Ninguno #Borrar la clave principal. & gt& gt& gtP.save(using='segundo') #Escribe un objeto nuevo.
El segundo método es utilizar la opción force_insert en el método save() para garantizar que Django ejecute INSERT SQL:
& gt& gt& gtp = Person(name = ' Fred ' )& gt ;& gt& gtp .save(using = 'first ')>& gt& gtp.save(using = 'segundo ', force_insert=True)
Esto asegura que la persona llamada Fred sea la Utilice la misma clave principal en la base de datos. Si la clave principal ya está ocupada al guardar en la segunda base de datos, se generará un error.
Selecciona la base de datos de la que eliminar datos.
Por defecto, la base de datos de la que se obtiene un objeto existente, la eliminación de este objeto también se realizará en esta base de datos:
& gt& gt& gtu = user objects . usuario_heredado'). get(username = 'Fred')>>& gtU.delete() #Se eliminará de la base de datos Legacy_users.
Al pasar el argumento de la palabra clave usando al método Model.delete(), puede definir en qué base de datos desea eliminar datos. El uso es similar al uso de este parámetro en el método save().
Por ejemplo, suponiendo que queremos mover usuarios de la base de datos Legacy_users a la base de datos new_users, podemos usar el siguiente comando:
& gt& gt& gtuser _ obj . ' new _ usuarios ')>& gt& gtuser_obj.delete(using='legacy_users')
Usar administradores en situaciones de múltiples bases de datos
Usar db_manager() en administradores permite la administración El servidor accede a una base de datos no predeterminada.
Por ejemplo, supongamos que tiene un administrador personalizado User.objects.create_user() que opera en una base de datos.
Debido a que create_user() es un método de administrador, no un conjunto de consultas, no puedes
usar objetos user . crear_usuario(). (método create_user().
Solo se puede usar en administradores de User.objects, no en conjuntos de consultas derivados de administradores). La solución es usar db_manager() de la siguiente manera:
p>objetos de usuario. db_manager('nuevos_usuarios').
CreateUser(...)
Db_manager() devuelve una copia del administrador vinculado a la base de datos especificada.
Utilice get_query_set() en caso de múltiples bases de datos.
Si sobrecarga get_query_set() en un administrador, asegúrese de llamar al mismo método en su clase principal (usando super()) o manejar correctamente el atributo _db en el administrador (contiene la cadena del nombre de la base de datos ).
Por ejemplo, si desea devolver una clase de conjunto de consultas personalizada desde el método get_query_set, puede hacer esto:
Clase MyManager (model. manager): def get_query_set(self): QS = CustomQuerySet(self.model)si self. _db no es Ninguno: qs = qs.using(self._db) devuelve qs
Uso de múltiples bases de datos en la interfaz de administración de Django
La interfaz de administración de Django obviamente no admite múltiples bases de datos. Si desea admitirlo, debe escribir un ModelAdmin personalizado.