mirror of
https://github.com/django/django.git
synced 2025-10-16 10:19:11 +00:00
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11908 bcc190cf-cafb-0310-a4f2-bffc1f526a37
139 lines
5.6 KiB
Plaintext
139 lines
5.6 KiB
Plaintext
.. _topics-db-multi-db:
|
|
|
|
==================
|
|
Multiple Databases
|
|
==================
|
|
|
|
.. versionadded:: 1.2
|
|
|
|
This topic guide describes Django's support for interacting with multiple
|
|
databases. Most of the rest of Django's documentation assumes you are
|
|
interacting with a single database. While none of this documentation is
|
|
incorrect, to fully interact with multiple databases additional steps must be
|
|
taken.
|
|
|
|
Defining Your Databases
|
|
=======================
|
|
|
|
The first step to using more than one database with Django is to tell Django
|
|
about the database servers you'll be using. This is done using the
|
|
:setting:`DATABASES` setting. This setting maps database aliases, which are
|
|
a way to refer to a specific database throughout Django, to a dictionary of
|
|
settings for that specific connection. The settings in the inner dictionaries
|
|
are described fully in the :setting:`DATABASES` documentation. The important
|
|
thing to note is that your primary database should have the alias
|
|
``'default'``, and any additional databases you have can have whatever alias
|
|
you choose. If at any time you attempt to access a database that isn't defined
|
|
in your :setting:`DATABASES` setting then Django will raise a
|
|
``django.db.utils.ConnectionDoesNotExist`` exception.
|
|
|
|
Selecting a Database for a ``QuerySet``
|
|
=======================================
|
|
|
|
It is possible to select the database for a ``QuerySet`` at any point during
|
|
it's construction. To choose the database that a query will be preformed
|
|
against simply call the ``using()`` method on the ``QuerySet`` with the sole
|
|
argument being the database alias.
|
|
|
|
Select a Database to Save a Model To
|
|
====================================
|
|
|
|
To choose what database to save a model to, provide a ``using`` keyword
|
|
argument to ``Model.save()``. For example if you had a user model that you
|
|
wanted to save to the ``'legacy_users'`` database you would do::
|
|
|
|
>>> user_obj.save(using='legacy_users')
|
|
|
|
To save the user.
|
|
|
|
Moving an object from one database to another
|
|
---------------------------------------------
|
|
|
|
If you have saved an instance to one database, it might be tempting to use
|
|
``save(using=...)`` as a way to migrate the instance to a new database. However,
|
|
if you don't take appropriate steps, this could have some unexpected consequences.
|
|
|
|
Consider the following example::
|
|
|
|
>>> p = Person(name='Fred')
|
|
>>> p.save(using='first') # (1)
|
|
# some other processing ...
|
|
>>> p.save(using='second') # (2)
|
|
|
|
In statement 1, a new Person object is saved to the ``first``
|
|
database. At this time, ``p`` doesn't have a primary key, so Django
|
|
issues a SQL ``INSERT`` statement. This creates a primary key, and
|
|
Django assigns that primary key to ``p``.
|
|
|
|
When the save occurs in statement 2, ``p`` already has a primary key
|
|
value, and Django will attempt to use that primary key on the new
|
|
database. If the primary key value isn't in use in the ``second``
|
|
database, then you won't have any problems -- the object will be
|
|
copied to the new databse.
|
|
|
|
However, if the primary key of ``p`` is already in use on the
|
|
``second`` database, the existing object on the ``second`` database
|
|
will be lost when ``p`` is saved.
|
|
|
|
There are two ways to avoid this outcome. Firstly, you can clear the
|
|
primary key of the instance. If an object has no primary key, Django
|
|
will treat it as a new object, avoiding any loss of data on the
|
|
``second`` database::
|
|
|
|
>>> p = Person(name='Fred')
|
|
>>> p.save(using='first')
|
|
# some other processing ...
|
|
>>> p.pk = None # Clear the PK
|
|
>>> p.save(using='second') # Write a completely new object
|
|
|
|
Secondly, you can use the ``force_insert`` option to ``save()`` to ensure that
|
|
Django does a SQL ``INSERT``::
|
|
|
|
>>> p = Person(name='Fred')
|
|
>>> p.save(using='first')
|
|
# some other processing ...
|
|
>>> p.save(using='second', force_insert=True)
|
|
|
|
This will ensure that the person named ``Fred`` will have the same
|
|
primary key on both databases. If that primary key is already in use
|
|
when you try to save onto the ``second`` database, an error will be
|
|
raised.
|
|
|
|
Select a Database to Delete a Model From
|
|
========================================
|
|
|
|
To select which database to delete a model from you also use a ``using``
|
|
keyword argument to the ``Model.delete()`` method, analogous to the ``using``
|
|
keyword argument to ``save()``. For example if you were migrating a user from
|
|
the ``'legacy_users'`` database to the ``'new_users'`` database you might do::
|
|
|
|
>>> user_obj.save(using='new_users')
|
|
>>> user_obj.delete(using='legacy_users')
|
|
|
|
|
|
Using ``Managers`` with Multiple Databases
|
|
==========================================
|
|
|
|
When you call ``using()`` Django returns a ``QuerySet`` that will be evaluated
|
|
against that database. However, sometimes you want to chain ``using()``
|
|
together with a cusotm manager method that doesn't return a ``QuerySet``,
|
|
such as the ``get_by_natural_key`` method. To solve this issue you can use the
|
|
``db_manager()`` method on a manager. This method returns a copy of the
|
|
*manager* bound to that specific database. This let's you do things like::
|
|
|
|
>>> Book.objects.db("other").get_by_natural_key(...)
|
|
|
|
If you are overiding ``get_query_set()`` on your manager you must be sure to
|
|
either, a) call the method on the parent (using ``super()``), or b) do the
|
|
appropriate handling of the ``_db`` attribute on the manager. For example if
|
|
you wanted to return a custom ``QuerySet`` class from the ``get_query_set``
|
|
method you could do this::
|
|
|
|
class MyManager(models.Manager):
|
|
...
|
|
def get_query_set(self):
|
|
qs = CustomQuerySet(self.model)
|
|
if self._db is not None:
|
|
qs = qs.using(self._db)
|
|
return qs
|