使用一个Django项目托管多个域

使用一个Django项目托管多个域,django,multi-tenant,Django,Multi Tenant,一般来说,我对Django和python都是新手,所以请耐心听我说。我想创建一个非常简单的SaaS应用程序来开始使用Django和python。我的设计要求所有域都在同一个代码库上运行。每个网站之间唯一不同的是数据库连接细节。(即每个域接收自己的数据库。所有数据库都包含相同的架构) 我该怎么跟Django谈?我看过网站框架,但我不确定这就是我想要的。基本上,我想 A) 当页面加载时,让Django从主数据库中查找数据库连接详细信息,然后在连接到站点数据库时使用这些详细信息 B) 每个站点有一个s

一般来说,我对Django和python都是新手,所以请耐心听我说。我想创建一个非常简单的SaaS应用程序来开始使用Django和python。我的设计要求所有域都在同一个代码库上运行。每个网站之间唯一不同的是数据库连接细节。(即每个域接收自己的数据库。所有数据库都包含相同的架构)

我该怎么跟Django谈?我看过网站框架,但我不确定这就是我想要的。基本上,我想

A) 当页面加载时,让Django从主数据库中查找数据库连接详细信息,然后在连接到站点数据库时使用这些详细信息

B) 每个站点有一个settings.py,并让django在运行时包含正确的文件(即settings\u domain.py)

C) 让索引WSGI包含基于访问域的适当设置文件(这似乎可以工作,但我确信我缺少此实现的一个潜在陷阱)

D) 其他一些我没有想到的实现


我是不是让事情变得更复杂了?如何在新的django项目中轻松实现此功能?

最好的方法是在您的Web服务器(无论是apache还是nginx)上进行重写/代理。在apache中,您可以使用类似这样的内容设置主机文件以捕获所有域。django将获得一个URL,在那里它可以确定它是哪个域

<VirtualHost *:80>
     ServerName domain.com
     ServerAlias *
     DocumentRoot /var/www/domain.com/DjangoProj/public

     Alias /media/ /var/www/domain.com/DjangoProj/misc/media/
     Alias /static/ /var/www/domain.com/DjangoProj/misc/static/

     <Directory /var/www/domain.com/DjangoProj/public>
         Order deny,allow
         Allow from all
     </Directory>

     WSGIScriptAlias / /var/www/domain.com/DjangoProj/app/wsgi.py

     <Directory /var/www/domain.com/DjangoProj/app>
     <Files wsgi.py>
     Order deny,allow
     Allow from all
     </Files>
     </Directory>

     <IfModule mod_rewrite.c>
          RewriteEngine on
          RewriteCond %{HTTP_HOST} ^(.*) [NC] # Catch domain
          RewriteCond %{REQUEST_URI} !userdomain [NC] # Don't rewrite if we already have it
          RewriteRule ^(.*)$ /userdomain/%1$1 [PT,L] # Pass in PT to give the URL back to mod_python!
     </IfModule>

     ErrorLog /var/www/domain.com/logs/error.log
     CustomLog /var/www/domain.com/logs/access.log combined
</VirtualHost>

ServerName域名.com
服务器别名*
DocumentRoot/var/www/domain.com/DjangoProj/public
别名/media//var/www/domain.com/DjangoProj/misc/media/
别名/static//var/www/domain.com/DjangoProj/misc/static/
命令拒绝,允许
通融
WSGIScriptAlias//var/www/domain.com/DjangoProj/app/wsgi.py
命令拒绝,允许
通融
重新启动发动机
重写cond%{HTTP_HOST}^(.*)[NC]#捕获域
重写cond%{REQUEST_URI}!userdomain[NC]#如果我们已经有了它,请不要重写
重写规则^(.*)$/userdomain/%1$1[PT,L]#传入PT将URL返回给mod_python!
ErrorLog/var/www/domain.com/logs/error.log
CustomLog/var/www/domain.com/logs/access.log

嗯,有一个有趣的项目在:。它试图让您拥有完全独特的站点,所有站点都运行在同一个项目上。然而,目前,我认为它不会对你有多大帮助,因为你需要比它提供的设置更多的定制

实际上,我自己就是这么做的,最初尝试使用django dynamicsites,但发现它有点过于敏感,不太适合我的项目。结果,我最终采取了一种稍微不同的方法

我的项目有一个“站点”模块,其中每个站点都有一个模块。每个模块都有自己的settings.py和url.py以及templates目录。例如:

sites
    - __init__.py
    - site1
        - __init__.py
        - settings.py
        - urls.py
        - templates
            - base.html
    - site 2
        - __init__.py
        - settings.py
        - urls.py
        - templates
            - base.html
每个settings.py大致如下所示:

from myproject.settings import *

SITE_ID = 1
URL_CONF = 'sites.site1.urls'

SITE_ROOT = os.path.dirname(__file__)
TEMPLATE_DIRS = (
    os.path.join(SITE_ROOT, 'templates')
)

CACHE_MIDDLEWARE_KEY_PREFIX = 'site1'
因此,这将导入项目设置文件,然后覆盖站点特有的设置。然后,您所要做的就是确保正在使用的任何服务器都加载特定站点的settings.py,而不是主项目settings.py。我使用的是nginx+Gunicorn的组合,下面是该配置的大致外观:

site1.conf(nginx)

我使用supervisor来管理Gunicorn服务器,下面是我的配置:

site1.conf(主管)


重要的一点是,没有花哨的Django中间件或类似的检查特定主机的方法,也没有相应的检查方法。您为uwsgi、Gunicorn等上的每个节点启动一个Django实例,指向right settings.py文件,您的Web服务器将每个子域的请求代理到匹配的上游连接。

此配置使用mod_python和apache2。但是这种想法可以转化为其他Web服务器配置。这种配置允许您动态添加站点,而无需使用不同的文件夹结构。用户可以将网站添加到框架中,而无需设置新的python文件。e、 g.
someuser.com
=>
yourdomain.com/userdomain/someuser.com
。然后你可以在你的urlconf中做任何自定义的事情,等等,然后用它做你喜欢的事情这听起来和我的想法很相似,但是我不能完全理解它(对Python和Django都很陌生)我理解捕获域并将其发送到wsgi,但我不确定Python端会发生什么,以包含正确的settings.py文件/连接到域的正确数据库。我的想法是,我们将加载一个唯一的settings.py,这取决于调用的域。每个settings.py都具有该域特有的数据库连接详细信息。你的想法听起来很相似,但我不确定如何最终确定它并使其生效。谢谢如果您希望每个域都有一个单独的数据库,那么这不是解决方案。这允许您为一个settings.py和数据库托管所有域,这是我最终发现的。那么,通过一个Django安装来托管多个具有多个数据库(每个站点唯一)的多个网站的解决方案是什么呢?为什么我不能为每个站点创建一个唯一的settings.py(带有相关的数据库连接详细信息),然后将每个域的index.wsgi指向正确的settings.py。那不行吗?本周末我将尝试建立一个测试服务器,并可以测试这个理论,但我想先找出是否有更好的方法。
upstream site1 {
    server 127.0.0.1:8001 fail_timeout=0;
}

server {
    listen 80;
    server_name site1.domain.com;

    root /path/to/project/root;

    location / {
        try_files $uri @proxy;
    }

    location @proxy {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 10;
        proxy_read_timeout 30;
        proxy_pass http://site1;
        proxy_redirect off;
    }

}
[program:site1]
command=/path/to/virtualenv/bin/python manage.py run_gunicorn --settings=sites.site1.settings
directory=/path/to/project/root
user=www-data
autostart=true
autorestart=true
redirect_stderr=True