如何为每个“应用程序实例”使用不同的数据库在姜戈?

发布于 2024-12-13 01:50:13 字数 1506 浏览 4 评论 0原文

场景

我们有两个应用程序。

TheApp

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

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

管理应用程序

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

问题

决定实例应使用哪个数据库连接的最佳方法是什么?执行什么操作 最好的?什么规模最好?

我想出的答案™

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

(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 但不是每个模型 但根据要求。

修改中间件中的设置

只是想到也许可以在中间件中更改数据库设置。还没有 了解中间件在 Django 中的工作原理以及其中的可能性。

一些晦涩的其他方式

因为我对 Django 还很陌生,所以我可能错过了一些要点,或者其中一些完全是错误的 又傻又坏。 jes^wyou 会怎么做?

为什么不将所有内容都放在一个数据库中呢?

出色地。因为我认为把东西分开是好的。如果发生不好的事情,并不是每个人都会突然受到影响。

The scenario

We have two applications.

TheApp

TheApp is an incredible app which customers love. Each customer gets his own
instance of the application, which means each customer will use a different database (name,user,password). The database connection should be decided on the domain from which the
request comes in.

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

Administration application

Should be able to create/delete TheApp instances for the customers. Therefore it has to setup the new database and write the config to somewhere. The way which decides
which db is used for the incoming request should perform well and be easy manageable.

The Question

Which is the best way to decide which database connection should be used for an instance? What performs
the best? What scales best?

Answers I came up with™

I read stuff and those are the ways I came up with:

(wsgi daemon + settings.py) per instance

Each customer will get his own settings.py with the database credentials. The settings
may inherit some common stuff from a shared settings file.

For each new setting file a new wsgi instance of the application has to be started.
This may scale badly if we have many customers? Also creating the apache vhost files
is ugly.

Using 'using' & one settings.py

I could do it like

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

and set THE_CURRENT_DB somewhere (middleware thingy?) per request. But it seems ugly to have to do this
everywhere. Also the settings.py/app has to be rewritten everytime a customer gets his
instance.

One settings.py + Application Router

I didn't yet have a look if I can access any information about the request in the router,
but if so, I maybe could decide which of the dbs in settings.py should be used. Kind of
like https://docs.djangoproject.com/en/1.3/topics/db/multi-db/#an-example but not per model
but per request.

Modify settings in a middleware

Just had the idea that maybe the db setting could be altered in a middleware. Didn't yet have
a look how middleware works in Django and what's possible there.

Some obscure other way

As I'm pretty new with Django I may have missed some points or some of them are just totally
silly and bad. What would jes^wyou do?

Why not everything in one db?

Well. Because I think separation of stuff is good. And if bad things happen not everybody is suddenly affected.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

只等公子 2024-12-20 01:50:13

这可以通过中间件和 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 会将所有内容放入公共模式中。您需要学习如何复制此架构以创建新架构,并习惯编写数据库更新脚本。

This is easily done with middleware and Postgres namespaces. Here is a quick and dirty example with absolutely no error handling:

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)

With this middleware enabled, each customer can have completely separate data, and no mopery is required to make it work. There are a few things to know, though:

  1. One problem is dealing with this in development. I usually add an if statement to ignore the above procedure if settings.DEBUG is True, but you could also set up virtual hosts and edit your hosts file to test this in development.
  2. Another consideration is that you must run a separate virtual host for each instance. Otherwise you may run into problems where instance data can cross over. I assume this is some sort of threading issue, but someone smarter than I can probably explain that in more detail.
  3. Finally, you need to think about how to deal with new installs and schema updates. Django will put everything in the public schema. You'll need to learn how to copy this schema to create a new one, and also get used to scripting database updates.
只有一腔孤勇 2024-12-20 01:50:13

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

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

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

That is one of those scenarios that show the weakness of django configuration module (settings). There is no "django supported" way to do that.

I think you could choose to go with an option that has minimal impact to code maintenance and portability. So I suggest to:

  • use an middleware to keep the users configuration in some data structure (django supported)
  • make settings.DATABASE a callable to fetch users configuration from above (django hack)
  • use django multiple database feature to access models (django supported)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文