Изначально Django предполагал работу только с одной базой данных (системное ограничение включающее такие вещи как группа настроек DATABASE_*). В течение всего этого времени явно ощущалась необходимость поддержки возможности работы с несколькими БД. В рамках работы над версией 1.2 в течение Google Summer of Code поддержка нескольких БД была включена в trunk. С этими новшествами связаны как целый ряд внутренних изменений, так и несколько удачных расширений для существующих интерфейсов работы с БД.

Интерфейс работы с несколькими БД

Наиболее заметное изменение в Django состоит в том, что, вместо того, чтобы писать настройки базы данных таким образом:

DATABASE_ENGINE = "postgresql_psycopg2"
DATABASE_NAME = "my_big_project"
DATABASE_USER = "mario"
DATABASE_PASSWORD = "princess_peach"

Вы пишете следующее:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        "NAME": "my_big_project",
        "USER": "mario",
        "PASSWORD": "princess_peach",
    },

    "credentials": {
        "ENGINE": "django.db.backends.oracle",
        "NAME": "users",
    }
}

В конечном итоге все проекты должны будут быть переведены в такой вид, хотя старый формат будет поддерживаться в Django вплоть до версии 1.4. Единственный ключ в словаре DATABASES, имеющий критическое значение, это «default» — «по умолчанию». Если вы используете базу данных, вам необходимо определить базу данных «default».

Теперь, когда вы сообщили Django о всех своих базах данных, надо найти способ сообщить Django о том, как их использовать. Первым изменением интерфейса в этой области является метод using(). using() принимает единственный параметр имя БД (имена БД служат ключами словаря DATABASES), и привязывает QuerySet к этой базе данных. Как и любое другое средство класса QuerySet, он может быть при необходимости поставлен в цепочку (как, например, метод order_by(), обновляющий результаты первого запроса при повторном запросе). По сути, это даёт вам возможность полностью контролировать, откуда будут читаться данные (а при ловком использовании методов create(), delete() и update() даёт даже возможность контролировать запись):

>>>User.objects.filter(username__startswith="admin").using("credentials")

Новые методы работы с данными класса QuerySet delete() и save() принимают дополнительный аргумент using, в который передаётся, опять же, имя БД.

Кроме того, появляется новый метод класса Managers, db_manager(), который тоже принимает имя БД. Его функция по сути близка функции метода using(). Основное различие заключается в следующем: вместо того, чтобы возвращать QuerySet, он возвращает новый Manager. Сценарий его использования делает возможным связать его в цепочку с теми методами класса Managers, которые не возвращают QuerySet (например, такими как create_user() класса UserManager).

Маршрутизаторы БД

Используя все эти методы, вы получаете возможность реализовать любую систему, использующую несколько баз данных. В том числе master-slave replication, partitioning и sharding. Однако, это не обязательно будет удобно. Вам придётся часто использовать в коде запросы к методу using(), что не лучшим образом совместимо с принципом реиспользуемых приложений Django (именно по этой причине опция using была удалена из класса модели Meta). Кроме того, в некоторых случаях класс QuerySet не полностью определён. Так, например, для получения доступа к данным класса User метод my_obj.user неявно создаст QuerySet, но методу using() будет некуда отправить запрос. Этим и было обусловлено появление концепции «маршрутизатора БД». Маршрутизаторы БД получают всю информацию о запросе, который вы хотите выполнить, и определяют, какую базу необходимо обратиться. Маршрутизаторы задаются в файле настроек в виде списка DATABASE_ROUTERS:

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

DATABASE_ROUTERS задаётся списком, поскольку маршрутизатор на любой стадии может вернуть значение None и тогда Django перейдет к следующему маршрутизатору из списка. Маршрутизаторы могу определять следующие методы:
  • db_for_read
  • db_for_write
  • allow_relation
  • allow_syncdb
Первые два метода очевидны, они возвращают имя БД, по отношению к которой выполняется запрос. Метод allow_relation призван контролировать разумность запросов. Django не позволит вам создать заведомо некорректные связи между БД. То есть, если вы попытаетесь создать взаимосвязь между двумя структурами данных из ��азных БД (для ForeignKey или для ManyToManyField), с помощью данного метода Django запросит необходимое подтверждение. И последний метод allow_syncdb позволяет определить, в какой из баз данных будет создана конкретная модель.

В документации Django по работе с несколькими БД, как всегда, приведена масса практических примеров. В том числе приведены примеры, описывающие, как начать применять распространённые паттерны с маршрутизаторами баз данных. Поддержка нескольких баз данных дает огромные преимущества и значительно расширяет области применения Django.