【问题标题】:How to use a different database per "application instance" in Django?如何在 Django 中为每个“应用程序实例”使用不同的数据库?
【发布时间】:2011-11-01 18:13:52
【问题描述】:

场景

我们有两个应用程序。

应用程序

TheApp 是一款深受客户喜爱的令人难以置信的应用。每个客户都有自己的 应用程序的实例,这意味着每个客户将使用不同的数据库(名称、用户、密码)。数据库连接应根据其所在的域来确定 请求进来了。

req: customerA.foo.tld -> db:(app_cust1, cust1, hunter2)
req: customerB.foo.tld -> db:(app_cust2, cust2, hunter3)

管理申请

应该能够为客户创建/删除 TheApp 实例。因此它必须设置新数据库并将配置写入somewhere。决定的方式 用于传入请求的 db 应该性能良好且易于管理。

问题

决定实例应该使用哪个数据库连接的最佳方法是什么?什么表现 最好的?什么规模最好?

我想出的答案™

我阅读了一些东西,这些是我想出的方法:

(wsgi 守护进程 + settings.py) 每个实例

每个客户都将获得自己的 settings.py 以及数据库凭据。设置 可能会从共享的设置文件中继承一些常见的东西。

对于每个新的设置文件,必须启动应用程序的新 wsgi 实例。 如果我们有很多客户,这可能会严重扩展吗?还创建 apache vhost 文件 很丑。

使用“使用”和一个 settings.py

我可以这样做

MyModel.objects.using(THE_CURRENT_DB).all()

并根据请求在某处设置THE_CURRENT_DB(中间件?)。但不得不这样做似乎很难看 到处。此外,每次客户获得他的客户时,都必须重写 settings.py/app 实例。

一个 settings.py + 应用路由器

我还没有查看是否可以访问路由器中有关请求的任何信息, 但如果是这样,我也许可以决定应该使用 settings.py 中的哪个数据库。有点儿 喜欢https://docs.djangoproject.com/en/1.3/topics/db/multi-db/#an-example,但不是每个型号 但根据要求。

修改中间件中的设置

刚刚想到也许可以在中间件中更改 db 设置。还没有 看看中间件在 Django 中是如何工作的以及那里有什么可能。

其他一些晦涩的方式

由于我对 Django 很陌生,我可能错过了一些要点,或者其中一些完全是 愚蠢和糟糕。 jes^w你会怎么做?

为什么不把所有东西都放在一个数据库里?

嗯。因为我认为东西的分离是好的。如果坏事发生,并不是每个人都会突然受到影响。

【问题讨论】:

  • 修改 django 设置可能是一个的想法。抱歉,我无法提供更多帮助并提供好主意;)
  • 顺便说一句,设置现在使用在 settings.py 中解释的环境变量,并确定客户特定的数据库和目录。它工作得很好。只需编写一个加载相关环境的 manage.py 包装器。客户的变量。我用 Fabric 做到了这一点。

标签: python django database-connection


【解决方案1】:

这可以通过中间件和 Postgres 命名空间轻松完成。这是一个绝对没有错误处理的快速而肮脏的示例:

class NamespaceMiddleware:
    def process_request(self, request):

        # Get the subdomain. You could also use the domain name, but you'll have to remove special characters.
        host = request.get_host()
        parts = host.split('.')
        if len(parts) >= 3:
            subdomain = parts[0]

        # Set the namespace (aka "schema"). This will throw a DatabaseError if the namespace does not exist.
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("SET search_path TO ", subdomain)

启用此中间件后,每个客户都可以拥有完全独立的数据,并且无需任何操作即可使其工作。不过有几点需要了解:

  1. 一个问题是在开发中处理这个问题。如果 settings.DEBUG 为 True,我通常会添加一个 if 语句来忽略上述过程,但您也可以设置虚拟主机并编辑主机文件以在开发中进行测试。
  2. 另一个考虑因素是您必须为每个实例运行单独的虚拟主机。否则,您可能会遇到实例数据可以交叉的问题。我认为这是某种线程问题,但比我更聪明的人可能会更详细地解释这一点。
  3. 最后,您需要考虑如何处理新安装和架构更新。 Django 会将所有内容放在公共模式中。您需要学习如何复制此架构以创建新架构,并习惯于编写数据库更新脚本。

【讨论】:

  • 关于 2):据我所知,这与线程本地存储有关。一些解决方案,例如django-tenant-schemas (github.com/bcarneiro/django-tenant-schemas) 使用 thread.local 来确保这一点。你有多确定使用 Vhost 是一个足够好的保障?
  • 为每个租户使用一个虚拟主机消除了我在生产中遇到的问题。我开始使用 django-tenant-schemas,但尚未投入生产。
  • 抱歉发表了对错误问题的评论..:(((是的,在我最初帖子的提供的链接中,租户是一个解决方案,但我找不到如何使用它的好例子. 如何在 apache 中自动创建 VirtualHosts。租户会解决医生从其他医生访问 url 的问题吗?我认为一个应用程序解决方案使用一个 urls.py 和一个设置文件,因此所有用户和医生的一切都是通用的他们是否属于 id 1 练习或 id 2 练习等。​​
【解决方案2】:

这是显示 django 配置模块(设置)弱点的场景之一。没有“django 支持”的方式来做到这一点。

我认为您可以选择对代码维护和可移植性影响最小的选项。所以我建议:

  • 使用中间件将用户配置保存在某些数据结构中(支持 django)
  • 将 settings.DATABASE 设为可调用以从上方获取用户配置 (django hack)
  • 使用 django 多数据库功能访问模型(django 支持)

【讨论】:

    猜你喜欢
    • 2021-10-13
    • 2011-09-26
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 2016-11-19
    • 2010-11-07
    • 2013-04-13
    相关资源
    最近更新 更多