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

В этом руководстве описывается поддержка 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все модели своих приложений, в том числе те, что используются во всех используемых вами 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': '[email protected]'
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

db_for_read( модель , ** подсказки )

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

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

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

db_for_write( модель , ** подсказки )

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

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

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

allow_relation( obj1 , obj2 , ** подсказки )

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

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

allow_migrate( db , app_label , model_name = None , ** подсказки )

Определите, разрешено ли выполнение операции миграции в базе данных с псевдонимом 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 пробует каждый маршрутизатор по очереди, пока не будет найдено предложение базы данных. Если предложение не найдено, он пробует текущий instance._state.dbэкземпляр подсказки. Если экземпляр подсказки не был предоставлен или instance._state.dbесть None, главный маршрутизатор выделит defaultбазу данных.

Пример

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

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

Этот пример не будет работать, если какая-либо из моделей myappсодержит отношения с моделями вне otherбазы данных. Отношения между базами данных создают проблемы ссылочной целостности, с которыми 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перед миграцией. См. В разделе Поведение приложений 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 выдает INSERTинструкцию SQL . Это создает первичный ключ, и 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()свой менеджер, обязательно вызовите метод родительского (using 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 приложений

Некоторые приложения 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 для каждой модели ( в том числе тех , которые не хранятся в этой базе данных).

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

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

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

Copyright ©2021 All rights reserved