<commit_before>.. _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. If you want to interact
with multiple databases, you'll need to take some additional steps.

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.

Databases can have any alias you choose. However, the alias
``default`` has special significance. Django uses the database with
the alias of ``default`` when no other database has been selected. If
you don't have a ``default`` database, you need to be careful to
always specify the database that you want to use.

The following is an example ``settings.py`` snippet defining two
databases -- a default PostgreSQL database and a MySQL database called
``users``:

.. code-block:: python

    DATABASES = {
        'default': {
            'NAME': 'app_data',
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'USER': 'postgres_user',
            'PASSWORD': '<PASSWORD>'
        },
        'users': {
            'NAME': 'user_data'
            'ENGINE': 'django.db.backends.mysql',
            'USER': 'mysql_user',
            'PASSWORD': '<PASSWORD>'
        }
    }

If you attempt to access a database that you haven't defined in your
:setting:`DATABASES` setting, Django will raise a
``django.db.utils.ConnectionDoesNotExist`` exception.

Synchronizing your databases
============================

The :djadmin:`syncdb` management command operates on one database at a
time. By default, it operates on the ``default`` database, but by
providing a :djadminopt:`--database` argument, you can tell syncdb to
synchronize a different database. So, to synchronize all models onto
all databases in our example, you would need to call::

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

If you don't want every application to be synchronized onto a
particular database. you can specify the :djadminopt:`--exclude`
argument to :djadmin:`syncdb`. The :djadminopt:`--exclude` option lets
you prevent a specific application or applications from being
synchronized. For example, if you don't want the ``sales`` application
to be in the ``users`` database, you could run::

    $ ./manage.py syncdb --database=users --exclude=sales

Alternatively, if you want fine-grained control of synchronization,
you can pipe all or part of the output of :djadmin:`sqlall` for a
particular application directly into your database prompt, like this::

	$ ./manage.py sqlall sales | ./manage.py dbshell

Using other management commands
-------------------------------

The other ``django-admin.py`` commands that interact with the database
operate in the same way as :djadmin:`syncdb` -- they only ever operate
on one database at a time, using :djadminopt:`--database` to control
the database used.

.. _topics-db-multi-db-routing:

Automatic database routing
==========================

The easiest way to use multiple databases is to set up a database
routing scheme. The default routing scheme ensures that objects remain
'sticky' to their original database (i.e., an object retrieved from
the ``foo`` database will be saved on the same database). However, you
can implement more interesting behaviors by defining a different
routing scheme.

Database routers
----------------

A database Router is a class that provides three methods:

.. method:: db_for_read(model, **hints)

    Suggest the database that should be used for read operations for
    objects of type ``model``.

    If a database operation is able to provide any additional
    information that might assist in selecting a database, it will be
    provided in the ``hints`` dictionary. Details on valid hints are
    provided :ref:`below <topics-db-multi-db-hints>`.

    Returns None if there is no suggestion.

.. method:: db_for_write(model, **hints)

    Suggest the database that should be used for writes of objects of
    type Model.

    If a database operation is able to provide any additional
    information that might assist in selecting a database, it will be
    provided in the ``hints`` dictionary. Details on valid hints are
    provided :ref:`below <topics-db-multi-db-hints>`.

    Returns None if there is no suggestion.

.. method:: allow_relation(obj1, obj2, **hints)

    Return True if a relation between obj1 and obj2 should be
    allowed, False if the relation should be prevented, or None if
    the router has no opinion. This is purely a validation operation,
    used by foreign key and many to many operations to determine if a
    relation should be allowed between two objects.

.. _topics-db-multi-db-hints:

Hints
~~~~~

The hints received by the database router can be used to decide which
database should receive a given request.

At present, the only hint that will be provided is ``instance``, an
object instance that is related to the read or write operation that is
underway. This might be the instance that is being saved, or it might
be an instance that is being added in a many-to-many relation. In some
cases, no instance hint will be provided at all. The router check for
the existence of an instance hint, and determine if hat hint should be
used to alter routing behavior.

Using routers
-------------

Database routers are installed using the :setting:`DATABASE_ROUTERS`
setting. This setting defines a list of class names, each specifying a
router that should be used by the master router
(``django.db.router``).

The master router is used by Django's database operations to allocate
database usage. Whenever a query needs to know which database to use,
it calls the master router, providing a model and a hint (if
available). Django then tries each router in turn until a database
suggestion can be found. If no suggestion can be found, it tries the
current ``_state.db`` of the hint instance. If a hint instance wasn't
provided, or the instance doesn't currently have database state, the
master router will allocate the ``default`` database.

An example
----------

.. admonition:: Example purposes only!

    This example is intended as a demonstration of how the router
    infrastructure can be used to alter database usage. It
    intentionally ignores some complex issues in order to
    demonstrate how routers are used.

    The approach of splitting ``contrib.auth`` onto a different
    database won't actually work on Postgres, Oracle, or MySQL with
    InnoDB tables. ForeignKeys to a remote database won't work due as
    they introduce referential integrity problems. If you're using
    SQLite or MySQL with MyISAM tables, there is no referential
    integrity checking, so you will be able to define cross-database
    foreign keys.

    The master/slave configuration described is also flawed -- it
    doesn't provide any solution for handling replication lag (i.e.,
    query inconsistencies introduced because of the time taken for a
    write to propagate to the slaves). It also doesn't consider the
    interaction of transactions with the database utiliztion strategy.

So - what does this mean in practice? Say you want ``contrib.auth`` to
exist on the 'credentials' database, and you want all other models in a
master/slave relationship between the databses 'master', 'slave1' and
'slave2'. To implement this, you would need 2 routers::

    class AuthRouter(object):
        """A router to control all database operations on models in
        the contrib.auth application"""

        def db_for_read(self, model, **hints):
            "Point all operations on auth models to 'credentials'"
            if model._meta.app_label == 'auth':
                return 'credentials'
            return None

        def db_for_write(self, model, **hints):
            "Point all operations on auth models to 'credentials'"
            if model._meta.app_label == 'auth':
                return 'credentials'
            return None

        def allow_relation(self, obj1, obj2, **hints):
            "Allow any relation if a model in Auth is involved"
            if obj1._meta.app_label == 'auth' or obj2._meta.app_label == 'auth':
                return True
            return None


     class MasterSlaveRouter(object):
        """A router that sets up a simple master/slave configuration"""

        def db_for_read(self, model, **hints):
            "Point all read operations to a random slave"
            return random.choice(['slave1','slave2'])<commit_msg>Fixed #12668 -- Corrected some typos in the multi-db docs. Thanks to mattimustang for the eagle eyes.<commit_after>.. _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. If you want to interact
with multiple databases, you'll need to take some additional steps.

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.

Databases can have any alias you choose. However, the alias
``default`` has special significance. Django uses the database with
the alias of ``default`` when no other database has been selected. If
you don't have a ``default`` database, you need to be careful to
always specify the database that you want to use.

The following is an example ``settings.py`` snippet defining two
databases -- a default PostgreSQL database and a MySQL database called
``users``:

.. code-block:: python

    DATABASES = {
        'default': {
            'NAME': 'app_data',
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'USER': 'postgres_user',
            'PASSWORD': '<PASSWORD>'
        },
        'users': {
            'NAME': 'user_data'
            'ENGINE': 'django.db.backends.mysql',
            'USER': 'mysql_user',
            'PASSWORD': '<PASSWORD>'
        }
    }

If you attempt to access a database that you haven't defined in your
:setting:`DATABASES` setting, Django will raise a
``django.db.utils.ConnectionDoesNotExist`` exception.

Synchronizing your databases
============================

The :djadmin:`syncdb` management command operates on one database at a
time. By default, it operates on the ``default`` database, but by
providing a :djadminopt:`--database` argument, you can tell syncdb to
synchronize a different database. So, to synchronize all models onto
all databases in our example, you would need to call::

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

If you don't want every application to be synchronized onto a
particular database. you can specify the :djadminopt:`--exclude`
argument to :djadmin:`syncdb`. The :djadminopt:`--exclude` option lets
you prevent a specific application or applications from being
synchronized. For example, if you don't want the ``sales`` application
to be in the ``users`` database, you could run::

    $ ./manage.py syncdb --database=users --exclude=sales

Alternatively, if you want fine-grained control of synchronization,
you can pipe all or part of the output of :djadmin:`sqlall` for a
particular application directly into your database prompt, like this::

	$ ./manage.py sqlall sales | ./manage.py dbshell

Using other management commands
-------------------------------

The other ``django-admin.py`` commands that interact with the database
operate in the same way as :djadmin:`syncdb` -- they only ever operate
on one database at a time, using :djadminopt:`--database` to control
the database used.

.. _topics-db-multi-db-routing:

Automatic database routing
==========================

The easiest way to use multiple databases is to set up a database
routing scheme. The default routing scheme ensures that objects remain
'sticky' to their original database (i.e., an object retrieved from
the ``foo`` database will be saved on the same database). However, you
can implement more interesting behaviors by defining a different
routing scheme.

Database routers
----------------

A database Router is a class that provides three methods:

.. method:: db_for_read(model, **hints)

    Suggest the database that should be used for read operations for
    objects of type ``model``.

    If a database operation is able to provide any additional
    information that might assist in selecting a database, it will be
    provided in the ``hints`` dictionary. Details on valid hints are
    provided :ref:`below <topics-db-multi-db-hints>`.

    Returns None if there is no suggestion.

.. method:: db_for_write(model, **hints)

    Suggest the database that should be used for writes of objects of
    type Model.

    If a database operation is able to provide any additional
    information that might assist in selecting a database, it will be
    provided in the ``hints`` dictionary. Details on valid hints are
    provided :ref:`below <topics-db-multi-db-hints>`.

    Returns None if there is no suggestion.

.. method:: allow_relation(obj1, obj2, **hints)

    Return True if a relation between obj1 and obj2 should be
    allowed, False if the relation should be prevented, or None if
    the router has no opinion. This is purely a validation operation,
    used by foreign key and many to many operations to determine if a
    relation should be allowed between two objects.

.. _topics-db-multi-db-hints:

Hints
~~~~~

The hints received by the database router can be used to decide which
database should receive a given request.

At present, the only hint that will be provided is ``instance``, an
object instance that is related to the read or write operation that is
underway. This might be the instance that is being saved, or it might
be an instance that is being added in a many-to-many relation. In some
cases, no instance hint will be provided at all. The router checks for
the existence of an instance hint, and determine if that hint should be
used to alter routing behavior.

Using routers
-------------

Database routers are installed using the :setting:`DATABASE_ROUTERS`
setting. This setting defines a list of class names, each specifying a
router that should be used by the master router
(``django.db.router``).

The master router is used by Django's database operations to allocate
database usage. Whenever a query needs to know which database to use,
it calls the master router, providing a model and a hint (if
available). Django then tries each router in turn until a database
suggestion can be found. If no suggestion can be found, it tries the
current ``_state.db`` of the hint instance. If a hint instance wasn't
provided, or the instance doesn't currently have database state, the
master router will allocate the ``default`` database.

An example
----------

.. admonition:: Example purposes only!

    This example is intended as a demonstration of how the router
    infrastructure can be used to alter database usage. It
    intentionally ignores some complex issues in order to
    demonstrate how routers are used.

    The approach of splitting ``contrib.auth`` onto a different
    database won't actually work on Postgres, Oracle, or MySQL with
    InnoDB tables. ForeignKeys to a remote database won't work due as
    they introduce referential integrity problems. If you're using
    SQLite or MySQL with MyISAM tables, there is no referential
    integrity checking, so you will be able to define cross-database
    foreign keys.

    The master/slave configuration described is also flawed -- it
    doesn't provide any solution for handling replication lag (i.e.,
    query inconsistencies introduced because of the time taken for a
    write to propagate to the slaves). It also doesn't consider the
    interaction of transactions with the database utilization strategy.

So - what does this mean in practice? Say you want ``contrib.auth`` to
exist on the 'credentials' database, and you want all other models in a
master/slave relationship between the databases 'master', 'slave1' and
'slave2'. To implement this, you would need 2 routers::

    class AuthRouter(object):
        """A router to control all database operations on models in
        the contrib.auth application"""

        def db_for_read(self, model, **hints):
            "Point all operations on auth models to 'credentials'"
            if model._meta.app_label == 'auth':
                return 'credentials'
            return None

        def db_for_write(self, model, **hints):
            "Point all operations on auth models to 'credentials'"
            if model._meta.app_label == 'auth':
                return 'credentials'
            return None

        def allow_relation(self, obj1, obj2, **hints):
            "Allow any relation if a model in Auth is involved"
            if obj1._meta.app_label == 'auth' or obj2._meta.app_label == 'auth':
                return True
            return None


     class MasterSlaveRouter(object):
        """A router that sets up a simple master/slave configuration"""

        def db_for_read(self, model, **hints):
            "Point all read operations to a random slave"
            return random.choice(['slave1','slave2'])
{'fraction_non_alphanumeric': 0.08611172444248179, 'fraction_numerical': 0.0020423934643409142, 'mean_word_length': 3.4295843520782396, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2104509', 'n_tokens_mistral': 4645, 'n_tokens_neox': 4432, 'n_words': 2364}