在我们公司,我们为相当多的本地报纸制作新闻门户网站(目前有13个,下个月将有30个,将来会有更多),每个页面每天有2到10万页的浏览量.由于我们正在从每个站点大量定制的情况发展到每个站点的配置或自定义模板的问题,我们的软件对于所有站点已经几乎相同.现在我们的部署策略是在16核服务器和12GB RAM上为每个站点(每个站点有1-17个工作站,具体取决于站点流量)的一个gunicorn实例.这种设置的问题是每个工作人员(常规预分叉炮弹)需要110MB,无论是否使用.现在有了新的站点,我们需要添加更多的RAM来提供更多的请求,所以基本上它不会扩展.此外,由于我们正在从每个站点独立的这个模型转移,每个站点都有自己的数据库,我非常喜欢它,特别是因为我们使用关系数据库(mysql,但迁移到pgsql),所以它更容易这样碎片.
我正在做一些研究和试验在一个gunicorn实例上运行所有站点,所以我可以完全使用服务器并在负载均衡器后面添加更多服务器.问题是django假设在很多地方每个进程只运行一个站点,所以对于我到目前为止我想到的,我必须实现:
这就是我想出来的,甚至没有实现它并看到它破坏的地方,我确信我需要更多的更改才能工作.所以我真的不想这样做,特别是我需要额外的维护工作,但我没有看到任何替代方案,并且很想知道有人已经以更好的方式解决了这个问题.当然我也可以完全停止使用django(我已经有很多理由这样做了)但这意味着重大改写并且有两个维护软件的两个不兼容的分支,直到新的一个与django版本达到功能奇偶校验,所以到我似乎比所有丑陋的黑客更糟糕.
我最近开发了一个具有类似要求的电子商务系统 - 从同一个项目运行的许多实例几乎可以共享所有内容.该系统的先前版本是一堆独立安装(~30),因此它非常难以维护.我确定要求仍然与您的要求不同(例如,在我的情况下,所有实例共享相同的模型),但分享我的经验可能仍然有用.
你是对的,Django没有开箱即用这样的场景,但实际上它很容易解决.这是我所做的简要描述.
我可以看到我想要达到的目标之间的协同作用django.contrib.sites.此外,因为许多第三方Django应用程序知道如何使用它并使用它,例如,生成当前站点的绝对URL.主要问题sites是它希望您指定当前站点ID settings.SITE_ID,这是一种非常天真的多主机问题方法.人们自然想要的,以及您还提到的是从Host请求标题中确定当前站点.为了解决这个问题,我从django-multisite以下网址借用了这个想法:https://github.com/shestera/django-multisite/blob/master/multisite/threadlocals.py#L19
接下来,我创建了一个应用程序,它封装了与项目的多主机方面相关的所有功能.在我的情况下,应用程序被调用stores,其中包括两个重要的类:stores.middleware.StoreMiddleware和stores.models.Store.
模型类是的子类django.contrib.sites.models.Site.子类化的好处Site是你可以将a传递Store给任何Site期望的函数.因此,您实际上仍然只是使用旧的,记录良好且经过测试的sites框架.Store我在课堂上添加了配置所有不同商店所需的所有字段.因此,它有一个像场urlconf,theme,robots_txt和诸如此类的东西.
中间件类的功能是将Host标头与Store数据库中的相应实例进行匹配.一旦Store检索到匹配,它将SITE_ID以类似于https://github.com/shestera/django-multisite/blob/master/multisite/middleware.py的方式修补.此外,它查看了store's urlconf,如果它不是None,它将设置request.urlconf应用其特殊的URL要求.之后,当前Store实例存储在request.store.这被证明是非常有用的,因为我能够在我的观点中做这样的事情:
def homepage(request):
featured = Product.objects.filter(featured=True, store=request.store)
...
Run Code Online (Sandbox Code Playgroud)
request.store在request整个项目中,我成为了对象的一个自然的额外维度.
在Store类上定义的另一件事是一个函数,get_absolute_url其实现看起来大致如下:
def get_absolute_url(self, to='/'):
"""
Return an absolute url to this `Store` or to `to` on this store.
The URL includes http:// and the domain name of the store.
`to` can be an object with `get_absolute_url()` or an absolute path as string.
"""
if isinstance(to, basestring):
path = to
elif hasattr(to, 'get_absolute_url'):
path = to.get_absolute_url()
else:
raise ValueError(
'Invalid argument (need a string or an object with get_absolute_url): %s' % to
)
url = 'http://%s%s%s' % (
self.domain,
# This setting allowed for a sane development environment
# where I just set it to ".dev:8000" and configured `dnsmasq`.
# The same value was also removed from the `Host` value in the middleware
# before looking up the `Store` in database.
settings.DOMAIN_SUFFIX,
path
)
return url
Run Code Online (Sandbox Code Playgroud)
因此,我可以轻松地为当前商店以外的对象生成URL,例如:
# Redirect to `product` on `store`.
redirect(store.get_absolute_url(product))
Run Code Online (Sandbox Code Playgroud)
基本上我只需要能够实现一个允许用户通过Django管理员创建一个新的电子商店的系统.