Spec-Zone.ru › Django 2.0

Базы данных

В этом руководстве описывается поддержка 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'
    }
}

Если понятие базы данных по умолчанию не имеет смысла в контексте вашего проекта, вам нужно быть внимательным, чтобы всегда указывать нужную базу данных. Django требует определения записи базы данных по умолчанию, но словарь параметров можно оставить пустым, если он не будет использоваться. Для этого необходимо настроить DATABASE_ROUTERS для всех моделей ваших приложений, включая модели из приложений contrib и сторонних приложений, которые вы используете, чтобы ни одна из запросов не направлялась в базу данных по умолчанию. Ниже приведен пример 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.db.utils.ConnectionDoesNotExist.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

db_for_read(model, **hints)

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

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

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

db_for_write(model, **hints)

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

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

Возвращает 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'. Обратите внимание, что это может быть историческая модель, и, следовательно, не имеет никаких пользовательских атрибутов, методов или менеджеров. Вы должны полагаться только на _meta.

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

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

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

Подсказки

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

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

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

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

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

Пример

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

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

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

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

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

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

Теперь нам нужно обработать маршрутизацию. Сначала нам нужен маршрутизатор, который знает, как отправлять запросы для приложения auth в auth_db.

class AuthRouter:
    """
    A router to control all database operations on models in the
    auth application.
    """
    def db_for_read(self, model, **hints):
        """
        Attempts to read auth models go to auth_db.
        """
        if model._meta.app_label == 'auth':
            return 'auth_db'
        return None

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

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

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth app only appears in the 'auth_db'
        database.
        """
        if app_label == 'auth':
            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_list = ('primary', 'replica1', 'replica2')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            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 перед миграцией. См. Поведение приложений contrib для получения информации о приложениях contrib, которые должны находиться вместе в одной базе данных.

Выбор базы данных вручную

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').all()

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

Выбор базы данных для 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
cursor = connections['my_db_alias'].cursor()

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

Связи между базами данных

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

END_OF_DOCUMENT_MARKER

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

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

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

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

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

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

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

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

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

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

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

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.0/topics/db/multi-db/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API