如何使用不同的数据库,每个“应用程序实例”在Django? [英] How to use a different database per "application instance" in Django?

查看:131
本文介绍了如何使用不同的数据库,每个“应用程序实例”在Django?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

方案



我们有两个应用程式。



TheApp



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

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



管理应用程式



应该能够为客户创建/删除TheApp实例。因此,它必须设置新数据库并将配置写入某处



问题













$ b

这是决定哪个数据库连接应该用于实例的最好方法?什么执行
最好?什么尺度最好?



答案我想出了



我读的东西,



(wsgi daemon + settings.py)每个客户将获得他自己的settings.py与数据库凭据。设置
可以从共享设置文件继承一些常见的东西。



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



使用'using'&一个settings.py



我可以像

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

并设置 THE_CURRENT_DB 某处(中间件事情?)每个请求。但是它似乎很丑的必须这样做
无处不在。此外,每当客户获得他的
实例时,必须重写settings.py/app。



一个settings.py +应用路由器



我还没有看看,如果我可以访问任何关于路由器中的请求,
的信息,但如果是这样,我也许可以决定哪些dbs在settings.py应该使用。种类
,例如 https://docs.djangoproject.com/ en / 1.3 / topics / db / multi-db /#an-example ,但不是根据模型
而是根据请求。



一个中间件



只是想到可能在中间件中更改db设置。



有些模糊的其他方式














由于我对Django很新,我可能错过了一些点,或者他们中的一些只是完全
愚蠢和坏。



为什么不是一个数据库中的一切?



好吧。因为我认为分离的东西是好的。

解决方案

这很容易用中间件和Postgres命名空间来完成。这里是一个快速和脏的例子,绝对没有错误处理:

  class NamespaceMiddleware:
def process_request ):

#获取子域。您还可以使用域名,但必须删除特殊字符。
host = request.get_host()
parts = host.split('。')
如果len(parts)> = 3:
subdomain = parts [0]

#设置命名空间(也称为schema)。如果命名空间不存在,这将抛出DatabaseError。
from django.db import connection
cursor = connection.cursor()
cursor.execute(SET search_path TO,subdomain)
pre>

在启用此中间件的情况下,每个客户可以拥有完全独立的数据,并且不需要使用mopery来使其工作。有几个事情要知道,虽然:


  1. 一个问题是在开发中处理这个问题。如果settings.DEBUG为True,我通常添加一个if语句以忽略上述过程,但您也可以设置虚拟主机并编辑您的主机文件以在开发中测试此文件。

  2. 是必须为每个实例运行单独的虚拟主机。否则,您可能会遇到实例数据可能交叉的问题。我假设这是某种线程问题,但是比我更聪明的人可以更详细地解释一下。

  3. 最后,你需要考虑如何处理新的安装和模式更新。 Django将把所有的东西放在公共模式中。您需要了解如何复制此模式以创建一个新模式,并且还可以用于编写数据库更新脚本。


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.

解决方案

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.

这篇关于如何使用不同的数据库,每个“应用程序实例”在Django?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆