Несколько баз данных

Это тематическое руководство описывает поддержку Django для взаимодействия с несколькими базами данных. Большая часть остальной документации Django предполагает, что вы взаимодействуете с одной базой данных. Если вы хотите взаимодействовать с несколькими базами данных, вам придется предпринять некоторые дополнительные шаги.

См.также

Информацию о тестировании с несколькими базами данных см. в Поддержка нескольких баз данных.

Определение ваших баз данных

Первый шаг к использованию более чем одной базы данных с Django - сообщить Django о серверах баз данных, которые вы будете использовать. Это делается с помощью параметра DATABASES. Эта настройка сопоставляет псевдонимы баз данных, которые являются способом обращения к конкретной базе данных в Django, со словарем настроек для этого конкретного соединения. Настройки во внутренних словарях полностью описаны в документации DATABASES.

Базы данных могут иметь любой выбранный вами псевдоним. Однако, псевдоним default имеет особое значение. Django использует базу данных с псевдонимом default, если не выбрана другая база данных.

Ниже приведен пример settings.py фрагмента, определяющего две базы данных - базу данных PostgreSQL по умолчанию и базу данных MySQL под названием users:

DATABASES = {
    "default": {
        "NAME": "app_data",
        "ENGINE": "django.db.backends.postgresql",
        "USER": "postgres_user",
        "PASSWORD": "s3krit",
    },
    "users": {
        "NAME": "user_data",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "priv4te",
    },
}

Если концепция базы данных default не имеет смысла в контексте вашего проекта, вам нужно быть внимательным, чтобы всегда указывать базу данных, которую вы хотите использовать. Django требует, чтобы была определена запись default базы данных, но словарь параметров можно оставить пустым, если она не будет использоваться. Для этого вы должны настроить DATABASE_ROUTERS для всех моделей вашего приложения, включая модели любых используемых вами приложений и приложений сторонних разработчиков, чтобы никакие запросы не направлялись к базе данных по умолчанию. Ниже приведен пример settings.py фрагмента, определяющего две базы данных не по умолчанию, при этом default запись намеренно оставлена пустой:

DATABASES = {
    "default": {},
    "users": {
        "NAME": "user_data",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "superS3cret",
    },
    "customers": {
        "NAME": "customer_data",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_cust",
        "PASSWORD": "veryPriv@ate",
    },
}

Если вы попытаетесь получить доступ к базе данных, которую вы не определили в настройках DATABASES, Django вызовет исключение django.utils.connection.ConnectionDoesNotExist.

Синхронизация баз данных

Команда управления migrate работает одновременно с одной базой данных. По умолчанию она работает с базой данных default, но, указав опцию --database, можно указать ей на синхронизацию другой базы данных. Так, для синхронизации всех моделей по всем базам данных в первом примере необходимо вызвать команду:

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

Если вы не хотите, чтобы каждое приложение было синхронизировано с определенной базой данных, вы можете определить database router, который реализует политику, ограничивающую доступность определенных моделей.

Если, как во втором примере, вы оставили базу данных default пустой, то при каждом запуске migrate необходимо указывать имя базы данных. Отсутствие имени базы данных приведет к ошибке. Для второго примера:

$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=customers

Использование других команд управления

Большинство других команд django-admin, взаимодействующих с базой данных, работают так же, как и migrate - они работают только с одной базой данных одновременно, используя --database для управления используемой базой данных.

Исключением из этого правила является команда makemigrations. Она проверяет историю миграций в базах данных, чтобы отловить проблемы с существующими файлами миграций (которые могут быть вызваны их редактированием) перед созданием новых миграций. По умолчанию она проверяет только базу данных default, но обращается к методу allow_migrate() и routers, если таковые установлены.

Автоматическая маршрутизация баз данных

Самый простой способ использовать несколько баз данных - настроить схему маршрутизации баз данных. Схема маршрутизации по умолчанию гарантирует, что объекты остаются «прилипшими» к своей исходной базе данных (т.е. объект, извлеченный из базы данных foo, будет сохранен в той же базе данных). Схема маршрутизации по умолчанию гарантирует, что если база данных не указана, все запросы возвращаются к базе данных default.

Вам не нужно ничего делать, чтобы активировать схему маршрутизации по умолчанию - она предоставляется «из коробки» в каждом проекте Django. Однако, если вы хотите реализовать более интересное поведение распределения баз данных, вы можете определить и установить свои собственные маршрутизаторы баз данных.

Маршрутизаторы баз данных

Маршрутизатор базы данных - это класс, который предоставляет до четырех методов:

db_for_read(model, **hints)

Предложите базу данных, которая должна использоваться для операций чтения объектов типа model.

Если операция с базой данных способна предоставить какую-либо дополнительную информацию, которая может помочь в выборе базы данных, она будет предоставлена в словаре hints. Подробности о допустимых подсказках приведены в below.

Возвращает None, если предложение отсутствует.

db_for_write(model, **hints)

Предложите базу данных, которая должна использоваться для записи объектов типа Model.

Если операция с базой данных способна предоставить какую-либо дополнительную информацию, которая может помочь в выборе базы данных, она будет предоставлена в словаре hints. Подробности о допустимых подсказках приведены в below.

Возвращает None, если предложение отсутствует.

allow_relation(obj1, obj2, **hints)

Возвращает True, если связь между obj1 и obj2 должна быть разрешена, False, если связь должна быть запрещена, или None, если маршрутизатор не имеет мнения. Это чисто проверочная операция, используемая внешним ключом и операциями «многие ко многим» для определения того, должна ли быть разрешена связь между двумя объектами.

Если ни один маршрутизатор не имеет мнения (т.е. все маршрутизаторы возвращают None), допускаются только отношения в пределах одной базы данных.

allow_migrate(db, app_label, model_name=None, **hints)

Определите, разрешена ли операция миграции для базы данных с псевдонимом db. Возвращает True, если операция должна быть запущена, False, если она не должна быть запущена, или None, если маршрутизатор не имеет мнения.

Позиционный аргумент app_label - это метка переносимого приложения.

model_name устанавливается большинством операций миграции в значение model._meta.model_name (строчная версия модели __name__) мигрируемой модели. Для операций None и RunPython его значение равно RunSQL, если только они не предоставляют его с помощью подсказок.

hints используются некоторыми операциями для передачи дополнительной информации маршрутизатору.

Когда установлено model_name, hints обычно содержит класс модели под ключом 'model'. Обратите внимание, что он может быть historical model, и, следовательно, не иметь никаких пользовательских атрибутов, методов или менеджеров. Вы должны полагаться только на _meta.

Этот метод также может быть использован для определения доступности модели на данной базе данных.

makemigrations всегда создает миграции для изменений модели, но если allow_migrate() возвращает False, любые операции миграции для model_name будут молча пропущены при выполнении migrate на db. Изменение поведения allow_migrate() для моделей, которые уже имеют миграции, может привести к неработающим внешним ключам, лишним таблицам или отсутствующим таблицам. Когда makemigrations проверяет историю миграций, он пропускает базы данных, в которые не разрешено мигрировать ни одному приложению.

Маршрутизатор не обязан предоставлять все эти методы - он может опустить один или несколько из них. Если один из методов опущен, Django пропустит этот маршрутизатор при выполнении соответствующей проверки.

Подсказки

Подсказки, полученные маршрутизатором баз данных, могут быть использованы для принятия решения о том, какая база данных должна получить данный запрос.

В настоящее время единственной подсказкой, которая будет предоставлена, является instance, экземпляр объекта, связанный с выполняемой операцией чтения или записи. Это может быть экземпляр, который сохраняется, или экземпляр, который добавляется в отношение «многие-ко-многим». В некоторых случаях подсказка экземпляра вообще не предоставляется. Маршрутизатор проверяет существование подсказки экземпляра и определяет, следует ли использовать эту подсказку для изменения поведения маршрутизации.

Использование маршрутизаторов

Маршрутизаторы базы данных устанавливаются с помощью настройки DATABASE_ROUTERS. Эта настройка определяет список имен классов, каждый из которых указывает маршрутизатор, который должен использоваться базовым маршрутизатором (django.db.router).

Базовый маршрутизатор используется операциями базы данных Django для распределения использования базы данных. Всякий раз, когда запрос должен знать, какую базу данных использовать, он обращается к базовому маршрутизатору, предоставляя модель и подсказку (если она доступна). Базовый маршрутизатор поочередно пробует каждый класс маршрутизаторов, пока один из них не вернет предложение базы данных. Если ни один маршрутизатор не возвращает предложение, базовый маршрутизатор пробует текущий instance._state.db экземпляр подсказки. Если экземпляр подсказки не был предоставлен, или instance._state.db является None, базовый маршрутизатор выделяет базу данных default.

Пример

Только для примера!

Этот пример предназначен для демонстрации того, как инфраструктура маршрутизаторов может быть использована для изменения использования базы данных. В нем намеренно игнорируются некоторые сложные вопросы, чтобы продемонстрировать, как используются маршрутизаторы.

Этот пример не будет работать, если какая-либо из моделей в myapp содержит связи с моделями вне базы данных other. В Cross-database relationships возникают проблемы ссылочной целостности, с которыми Django в настоящее время не может справиться.

Описанная конфигурация основной/реплика (в некоторых базах данных называемая ведущей/ведомой) также несовершенна - она не предоставляет никакого решения для обработки задержки репликации (т.е. несоответствий запросов, возникающих из-за времени, необходимого для распространения записи на реплики). В нем также не рассматривается взаимодействие транзакций со стратегией использования базы данных.

Итак, что это означает на практике? Рассмотрим еще один пример конфигурации. В этой конфигурации будет несколько баз данных: одна для приложения auth, а все остальные приложения используют первичную/реплику с двумя копиями для чтения. Вот настройки, определяющие эти базы данных:

DATABASES = {
    "default": {},
    "auth_db": {
        "NAME": "auth_db_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "swordfish",
    },
    "primary": {
        "NAME": "primary_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "spam",
    },
    "replica1": {
        "NAME": "replica1_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "eggs",
    },
    "replica2": {
        "NAME": "replica2_name",
        "ENGINE": "django.db.backends.mysql",
        "USER": "mysql_user",
        "PASSWORD": "bacon",
    },
}

Теперь нам нужно разобраться с маршрутизацией. Сначала нам нужен маршрутизатор, который знает, что нужно посылать запросы для приложений auth и contenttypes в auth_db (модели auth связаны с ContentType, поэтому они должны храниться в одной базе данных):

class AuthRouter:
    """
    A router to control all database operations on models in the
    auth and contenttypes applications.
    """

    route_app_labels = {"auth", "contenttypes"}

    def db_for_read(self, model, **hints):
        """
        Attempts to read auth and contenttypes models go to auth_db.
        """
        if model._meta.app_label in self.route_app_labels:
            return "auth_db"
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth and contenttypes models go to auth_db.
        """
        if model._meta.app_label in self.route_app_labels:
            return "auth_db"
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the auth or contenttypes apps is
        involved.
        """
        if (
            obj1._meta.app_label in self.route_app_labels
            or obj2._meta.app_label in self.route_app_labels
        ):
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth and contenttypes apps only appear in the
        'auth_db' database.
        """
        if app_label in self.route_app_labels:
            return db == "auth_db"
        return None

И нам также нужен маршрутизатор, который отправляет все другие приложения к конфигурации основной/реплики, и случайным образом выбирает реплику для чтения из:

import random


class PrimaryReplicaRouter:
    def db_for_read(self, model, **hints):
        """
        Reads go to a randomly-chosen replica.
        """
        return random.choice(["replica1", "replica2"])

    def db_for_write(self, model, **hints):
        """
        Writes always go to primary.
        """
        return "primary"

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the primary/replica pool.
        """
        db_set = {"primary", "replica1", "replica2"}
        if obj1._state.db in db_set and obj2._state.db in db_set:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True

Наконец, в файл настроек мы добавляем следующее (заменяя path.to. реальным Python-путем к модулю (модулям), где определены маршрутизаторы):

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

Порядок, в котором обрабатываются маршрутизаторы, имеет значение. Маршрутизаторы будут запрашиваться в том порядке, в котором они перечислены в настройке DATABASE_ROUTERS. В данном примере параметр AuthRouter обрабатывается раньше, чем PrimaryReplicaRouter, и в результате решения, касающиеся моделей в параметре auth, обрабатываются до принятия любого другого решения. Если бы параметр DATABASE_ROUTERS перечислял два маршрутизатора в другом порядке, то первым обрабатывался бы параметр PrimaryReplicaRouter.allow_migrate(). Всеобъемлющий характер реализации PrimaryReplicaRouter означает, что все модели будут доступны во всех базах данных.

После установки этой системы и переноса всех баз данных в соответствии с требованиями Синхронизация баз данных, запустим код Django:

>>> # This retrieval will be performed on the 'auth_db' database
>>> fred = User.objects.get(username="fred")
>>> fred.first_name = "Frederick"

>>> # This save will also be directed to 'auth_db'
>>> fred.save()

>>> # These retrieval will be randomly allocated to a replica database
>>> dna = Person.objects.get(name="Douglas Adams")

>>> # A new object has no database allocation when created
>>> mh = Book(title="Mostly Harmless")

>>> # This assignment will consult the router, and set mh onto
>>> # the same database as the author object
>>> mh.author = dna

>>> # This save will force the 'mh' instance onto the primary database...
>>> mh.save()

>>> # ... but if we re-retrieve the object, it will come back on a replica
>>> mh = Book.objects.get(title="Mostly Harmless")

В этом примере определен маршрутизатор для обработки взаимодействия с моделями из приложения auth, и другие маршрутизаторы для обработки взаимодействия со всеми остальными приложениями. Если вы оставили свою базу данных default пустой и не хотите определять маршрутизатор для обработки всех приложений, не указанных иначе, ваши маршрутизаторы должны обрабатывать имена всех приложений в INSTALLED_APPS перед миграцией. Смотрите Поведение приложений вклада для получения информации о приложениях, которые должны находиться в одной базе данных.

Ручной выбор базы данных

Django также предоставляет API, который позволяет вам полностью контролировать использование базы данных в вашем коде. Выделенная вручную база данных будет иметь приоритет над базой данных, выделенной маршрутизатором.

Ручной выбор базы данных для QuerySet

Вы можете выбрать базу данных для QuerySet в любой точке «цепочки» QuerySet. Вызовите using() на QuerySet, чтобы получить другой QuerySet, который использует указанную базу данных.

using() принимает один аргумент: псевдоним базы данных, к которой необходимо выполнить запрос. Например:

>>> # This will run on the 'default' database.
>>> Author.objects.all()

>>> # So will this.
>>> Author.objects.using("default")

>>> # This will run on the 'other' database.
>>> Author.objects.using("other")

Выбор базы данных для save()

Используйте ключевые слова using и Model.save(), чтобы указать, в какую базу данных должны быть сохранены данные.

Например, для сохранения объекта в базу данных legacy_users используется следующее:

>>> my_object.save(using="legacy_users")

Если вы не укажете using, метод save() будет сохранять в базу данных по умолчанию, выделенную маршрутизаторами.

Перемещение объекта из одной базы данных в другую

Если вы сохранили экземпляр в одной базе данных, может возникнуть соблазн использовать save(using=...) как способ переноса экземпляра в новую базу данных. Однако если не предпринять соответствующих шагов, это может привести к неожиданным последствиям.

Рассмотрим следующий пример:

>>> p = Person(name="Fred")
>>> p.save(using="first")  # (statement 1)
>>> p.save(using="second")  # (statement 2)

В операторе 1 новый объект Person сохраняется в базе данных first. На данный момент у p нет первичного ключа, поэтому Django выдает SQL-оператор INSERT. Это создает первичный ключ, и Django присваивает этот первичный ключ объекту p.

Когда происходит сохранение в операторе 2, p уже имеет значение первичного ключа, и Django попытается использовать этот первичный ключ в новой базе данных. Если значение первичного ключа не используется в базе данных second, то у вас не будет никаких проблем - объект будет скопирован в новую базу данных.

Однако, если первичный ключ p уже используется в базе данных second, существующий объект в базе данных second будет переопределен при сохранении p.

Избежать этого можно двумя способами. Во-первых, можно очистить первичный ключ экземпляра. Если объект не имеет первичного ключа, Django будет рассматривать его как новый объект, что позволит избежать потери данных в базе second:

>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.pk = None  # Clear the primary key.
>>> p.save(using="second")  # Write a completely new object.

Второй вариант - использовать опцию force_insert к save() для того, чтобы Django выполнил SQL INSERT:

>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.save(using="second", force_insert=True)

Это гарантирует, что человек с именем Fred будет иметь один и тот же первичный ключ в обеих базах данных. Если этот первичный ключ уже используется при попытке сохранения в базе данных second, будет выдана ошибка.

Выбор базы данных для удаления

По умолчанию вызов удаления существующего объекта будет выполняться на той же базе данных, которая использовалась для получения объекта:

>>> u = User.objects.using("legacy_users").get(username="fred")
>>> u.delete()  # will delete from the `legacy_users` database

Чтобы указать базу данных, из которой будет удалена модель, передайте аргумент с ключевым словом using в метод Model.delete(). Этот аргумент работает так же, как и аргумент using с ключевым словом в методе save().

Например, при переносе пользователя из базы данных legacy_users в базу данных new_users можно использовать следующие команды:

>>> user_obj.save(using="new_users")
>>> user_obj.delete(using="legacy_users")

Использование менеджеров с несколькими базами данных

Используйте метод db_manager() для менеджеров, чтобы предоставить менеджерам доступ к базе данных не по умолчанию.

Например, допустим, у вас есть пользовательский метод менеджера, который обращается к базе данных - User.objects.create_user(). Поскольку create_user() является методом менеджера, а не методом QuerySet, вы не можете сделать User.objects.using('new_users').create_user(). (Метод create_user() доступен только для User.objects, менеджера, а не для QuerySet объектов, производных от менеджера). Решением является использование метода db_manager(), например, так:

User.objects.db_manager("new_users").create_user(...)

db_manager() возвращает копию менеджера, привязанную к указанной вами базе данных.

Использование get_queryset() с несколькими базами данных

Если вы переопределяете get_queryset() на вашем менеджере, убедитесь, что вы либо вызываете метод на родителе (используя super()), либо выполняете соответствующую обработку атрибута _db на менеджере (строка, содержащая имя используемой базы данных).

Например, если вы хотите вернуть пользовательский класс QuerySet из метода get_queryset, вы можете сделать следующее:

class MyManager(models.Manager):
    def get_queryset(self):
        qs = CustomQuerySet(self.model)
        if self._db is not None:
            qs = qs.using(self._db)
        return qs

Использование нескольких баз данных в интерфейсе администратора Django

В админке Django нет явной поддержки нескольких баз данных. Если вы хотите предоставить интерфейс администратора для модели на базе данных, отличной от той, которая указана в вашей цепочке маршрутизации, вам нужно будет написать пользовательские ModelAdmin классы, которые будут направлять администратора на использование конкретной базы данных для контента.

Объекты ModelAdmin имеют следующие методы, которые требуют настройки для поддержки нескольких баз данных:

class MultiDBModelAdmin(admin.ModelAdmin):
    # A handy constant for the name of the alternate database.
    using = "other"

    def save_model(self, request, obj, form, change):
        # Tell Django to save objects to the 'other' database.
        obj.save(using=self.using)

    def delete_model(self, request, obj):
        # Tell Django to delete objects from the 'other' database
        obj.delete(using=self.using)

    def get_queryset(self, request):
        # Tell Django to look for objects on the 'other' database.
        return super().get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super().formfield_for_foreignkey(
            db_field, request, using=self.using, **kwargs
        )

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super().formfield_for_manytomany(
            db_field, request, using=self.using, **kwargs
        )

Представленная здесь реализация реализует стратегию использования нескольких баз данных, при которой все объекты данного типа хранятся в определенной базе данных (например, все объекты User находятся в базе данных other). Если ваше использование нескольких баз данных более сложное, ваша ModelAdmin должна отражать эту стратегию.

С объектами InlineModelAdmin можно работать аналогичным образом. Для них требуется три специализированных метода:

class MultiDBTabularInline(admin.TabularInline):
    using = "other"

    def get_queryset(self, request):
        # Tell Django to look for inline objects on the 'other' database.
        return super().get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super().formfield_for_foreignkey(
            db_field, request, using=self.using, **kwargs
        )

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super().formfield_for_manytomany(
            db_field, request, using=self.using, **kwargs
        )

Как только вы написали определения администраторов модели, их можно зарегистрировать в любом экземпляре Admin:

from django.contrib import admin


# Specialize the multi-db admin objects for use with specific models.
class BookInline(MultiDBTabularInline):
    model = Book


class PublisherAdmin(MultiDBModelAdmin):
    inlines = [BookInline]


admin.site.register(Author, MultiDBModelAdmin)
admin.site.register(Publisher, PublisherAdmin)

othersite = admin.AdminSite("othersite")
othersite.register(Publisher, MultiDBModelAdmin)

Этот пример устанавливает два сайта администратора. На первом сайте открыты объекты Author и Publisher; объекты Publisher имеют табличную вставку, показывающую книги, опубликованные данным издателем. Второй сайт раскрывает только издателей, без встроенных элементов.

Использование необработанных курсоров с несколькими базами данных

Если вы используете более одной базы данных, вы можете использовать django.db.connections для получения соединения (и курсора) для конкретной базы данных. django.db.connections - это объект типа словаря, который позволяет вам получить конкретное соединение, используя его псевдоним:

from django.db import connections

with connections["my_db_alias"].cursor() as cursor:
    ...

Ограничения, связанные с использованием нескольких баз данных

Межбазовые отношения

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

Это происходит из-за ссылочной целостности. Для того чтобы поддерживать связь между двумя объектами, Django необходимо знать, что первичный ключ связанного объекта действителен. Если первичный ключ хранится в отдельной базе данных, то невозможно легко оценить действительность первичного ключа.

Если вы используете Postgres, Oracle или MySQL с InnoDB, это обеспечивается на уровне целостности базы данных - ключевые ограничения на уровне базы данных предотвращают создание отношений, которые не могут быть проверены.

Однако, если вы используете SQLite или MySQL с таблицами MyISAM, то принудительная ссылочная целостность отсутствует; в результате вы можете «подделать» перекрестные внешние ключи базы данных. Однако такая конфигурация официально не поддерживается Django.

Поведение приложений вклада

Несколько приложений contrib включают модели, и некоторые приложения зависят от других. Поскольку межбазовые связи невозможны, это создает некоторые ограничения на то, как вы можете разделить эти модели по базам данных:

  • каждый из contenttypes.ContentType, sessions.Session и sites.Site может быть сохранен в любой базе данных, при наличии подходящего маршрутизатора.
  • Модели auth - User, Group и Permission - связаны между собой и связаны с ContentType, поэтому они должны храниться в той же базе данных, что и ContentType.
  • admin зависит от auth, поэтому его модели должны находиться в той же базе данных, что и auth.
  • flatpages и redirects зависят от sites, поэтому их модели должны находиться в той же базе данных, что и sites.

Кроме того, некоторые объекты автоматически создаются сразу после того, как migrate создает таблицу для их хранения в базе данных:

  • по умолчанию Site,
  • a ContentType для каждой модели (включая те, которые не хранятся в этой базе данных),
  • Permissions для каждой модели (включая те, которые не хранятся в этой базе данных).

Для распространенных настроек с несколькими базами данных не имеет смысла иметь эти объекты в нескольких базах данных. К распространенным настройкам относятся первичная/репликативная база данных и подключение к внешним базам данных. Поэтому рекомендуется написать database router, который позволяет синхронизировать эти три модели только с одной базой данных. Используйте тот же подход для приложений contrib и сторонних приложений, которым не нужны их таблицы в нескольких базах данных.

Предупреждение

Если вы синхронизируете типы содержимого с несколькими базами данных, имейте в виду, что их первичные ключи могут не совпадать в разных базах данных. Это может привести к повреждению или потере данных.

Вернуться на верх