【问题标题】:Django multiple and dynamic databasesDjango 多动态数据库
【发布时间】:2011-09-28 22:43:30
【问题描述】:

我一直在评估 django,想知道以下是否可行。我已经查看了常规的多数据库文档,所以请不要指出这一点,因为据我所知没有提到这个用例。如果我错了,我把它收回:)

我想要一个主数据库,我的应用程序的大部分模型都将驻留在其中,但是其中一个应用程序需要动态创建数据库,这些数据库将是客户特定的数据库。

数据库路径(我打算使用 sqlite)将存储在主数据库中,因此需要更改光标但模型将保持不变。

我欢迎任何关于如何实现这一目标的想法?

【问题讨论】:

  • 为什么必须使用多个数据库?您是否有理由无法调整您的应用模型架构以保存每个客户的信息?为每个客户拥有多个数据库是非常不规则的。
  • 我目前正在尝试确定合适的架构。我不必使用多个数据库,但它是提供可移植、在线和离线服务的一种选择。为此,我想知道它是否可能,这在概念上相当简单,但我知道在实践中在一般框架中支持这一点可能会很棘手,所以我想我会看看是否有人以前做过这样的事情。
  • Django: dynamic database file 的可能重复项(注意:链接的问题似乎提供了一个适当的解决方案,不需要在添加/更改/删除新数据库时重新启动服务器的解决方法)跨度>

标签: django django-database


【解决方案1】:

我将使用“You should not edit settings at runtime”打开。

话虽如此,我也有同样的问题,我想为每个用户创建一个唯一的数据库。这样做的原因是我为用户提供了保存/访问/访问未存储在我的服务器上的数据库的能力,这需要拥有多个数据库,因此每个用户都有一个。

此答案不是实现预期目标的推荐方法。我很想听听 django-guru 如何最好地解决这个问题。但是,这是我一直在使用的解决方案,到目前为止效果很好。我正在使用 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 语句将数据加载到设置中。这应该没问题,但是如果您在其中一个文件中发现了一些损坏或恶意代码,您将是一只可悲的熊猫。

请注意,我仍然使用默认数据库存储身份验证和会话数据,但我自己的应用程序中的所有数据都存储在用户特定的数据库中。

【讨论】:

  • 我提供了一个不同的解决方案,尽管我已经实现了您的方法(通过文件)和我的方法,使用数据库本身作为这些文件的存储。 settings.py 的最后一行加载所有包含数据库定义的模型,并将它们添加到 django 的 DATABASE 设置中。
  • 如果您在主数据库(用于管理用户的数据库)中编写数据库连接,则可以使其比文本文件更优雅。
  • 同样的程序是否也适用于“油门限制”?
  • 您能分享一下您是如何实现这一目标的吗?您能否在回答 GeorgeSilva 和 @JulienD 时分享脚本作为示例,我正在尝试这个。
  • @Gary 我的意思是,在存储您的用户(或项目或其他)的“主”数据库中,您可以添加一个名为“个人”数据库​​的列,该数据库应用于那个用户。然后,当应用程序为用户执行时,它会从“主”数据库中读取数据库名称,并使用它打开与“个人”数据库​​的连接。这使得通过访问您自己的(安全)API 在执行时切换数据库成为可能。
【解决方案2】:

为了增加@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

【讨论】:

    猜你喜欢
    • 2014-07-16
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 2018-04-12
    • 2012-12-24
    • 2012-04-12
    • 2021-08-05
    • 2014-04-03
    相关资源
    最近更新 更多