Pull to refresh

Multiple database support

Reading time4 min
Views8.7K
Original author: Alex Gaynor
Изначально 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.
Tags:
Hubs:
Total votes 55: ↑47 and ↓8+39
Comments6

Articles