Django несколько динамических баз данных - PullRequest
32 голосов
/ 05 июля 2011

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

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

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

Я бы приветствовал любые мысли о способах достижения этого?

Ответы [ 2 ]

29 голосов
/ 02 июля 2012

Я открою с " Вы не должны редактировать настройки во время выполнения ".

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

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

Таким образом, это процесс:

  1. Добавить новую базу данных в настройки (во время выполнения)
  2. Создать файл для хранения этих настроек для перезагрузки при перезапуске сервера (во время выполнения)
  3. Запустить скрипт, который загружает сохраненные файлы настроек (всякий раз, когда сервер перезагружается)

Теперь, как этого добиться:

1) Во-первых, когда создается новый пользователь, я создаю новую базу данных в настройках. Этот код живет, на мой взгляд, там, где создаются новые пользователи.

from YOUR_PROJECT_NAME import settings
database_id = user.username #just something unique
newDatabase = {}
newDatabase["id"] = database_id
newDatabase['ENGINE'] = 'django.db.backends.sqlite3'
newDatabase['NAME'] = '/path/to/db_%s.sql' % database_id
newDatabase['USER'] = ''
newDatabase['PASSWORD'] = ''
newDatabase['HOST'] = ''
newDatabase['PORT'] = ''
settings.DATABASES[database_id] = newDatabase
save_db_settings_to_file(newDatabase) #this is for step 2)

Этот скрипт загружает настройки базы данных «во время выполнения» в настройки проекта django. Однако, если сервер будет перезапущен, эта база данных больше не будет в настройках.

2) Чтобы облегчить автоматическую перезагрузку этих настроек при каждом перезапуске сервера, я создаю файл для каждой базы данных, который будет загружаться при каждом запуске сервера. Создание этого файла выполняется функцией save_db_settings_to_file:

def save_db_settings_to_file(db_settings):
    path_to_store_settings = "/path/to/your/project/YOUR_PROJECT_NAME/database_settings/"
    newDbString = """
DATABASES['%(id)s'] = {
    'ENGINE': '%(ENGINE)s', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
    'NAME': '%(NAME)s',                      # Or path to database file if using sqlite3.
    'USER': '',                      # Not used with sqlite3.
    'PASSWORD': '',                  # Not used with sqlite3.
    'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
    'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
}
    """ % db_settings
    file_to_store_settings = os.path.join(path_to_store_settings, db_settings['id'] + ".py")
    write_file(file_to_store_settings, newDbString) #psuedocode for compactness

3) Чтобы фактически загрузить эти настройки при запуске сервера, я добавляю одну строку в самый низ /path/to/your/project/YOUR_PROJECT_NAME/settings.py, которая загружает каждый файл в папке настроек и запускает его, что приводит к загрузке данных базы данных. в настройки.

import settings_manager

Затем import settings_manager загрузит файл в /path/to/your/project/YOUR_PROJECT_NAME/settings_manager.py, который содержит следующий код:

from settings import DATABASES
import os

path_to_store_settings = "/path/to/your/project/YOUR_PROJECT_NAME/database_settings/"
for fname in os.listdir(path_to_settings):
    full_path = os.path.join(path_to_settings, fname)
    f = open(full_path)
    content = f.read()
    f.close()
    exec(content) #you'd better be sure that the file doesn't contain anything malicious

Обратите внимание, что вы можете поместить этот код прямо в конец файла settings.py вместо оператора import, но при использовании оператора import поддерживается уровень абстракции settings.py.

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

Как я уже сказал, это работает, и я до сих пор успешно использовал его, но это НЕ идеальное решение. Я был бы очень признателен, если бы кто-нибудь смог опубликовать лучшее решение.

Что в этом плохого:

  • Он явно не поддается совету команды django не изменять настройки во время выполнения. Я не знаю причину, по которой дается этот совет.
  • Он использует оператор exec для загрузки данных в настройки. Это должно быть хорошо, но если вы получите какой-нибудь поврежденный или вредоносный код в одном из этих файлов, вы будете грустной пандой.

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

8 голосов
/ 06 марта 2015

Чтобы дополнить ответ @ thedawnrider, в некоторых случаях редактирования settings.DATABASES может быть недостаточно. Может быть более надежным редактировать django.db.connections.databases, который служит кешем и оболочкой для settings.DATABASES.

, например

from django.db import connections
database_id = user.username #just something unique
newDatabase = {}
newDatabase["id"] = database_id
newDatabase['ENGINE'] = 'django.db.backends.sqlite3'
newDatabase['NAME'] = '/path/to/db_%s.sql' % database_id
newDatabase['USER'] = ''
newDatabase['PASSWORD'] = ''
newDatabase['HOST'] = ''
newDatabase['PORT'] = ''
connections.databases[database_id] = newDatabase
...