我正在尝试将我的Django应用设置为多个域(同时提供略有不同的内容) 我写了这个中间件:
class MultiSiteMiddleware(object):
def process_request(self, request):
host = request.get_host()
host_part = host.split(':')[0].split('.com')[0].split('.')
host = host_part[len(host_part)-1] + '.com'
site = Site.objects.get(domain=host)
settings.SITE_ID = site.id
settings.CURRENT_HOST = host
Site.objects.clear_cache()
return
在视图中我使用它:
def get_site(request):
current_site = get_current_site(request)
return current_site.name
def view(request, pk):
site = get_site(request)
if site == 'site1':
# serve content1
...
elif site == 'site2'
# serve content2
...
但现在有404个错误(我有时会在日志中找到它们,在手动浏览我的网站时看不到它们)它们本身不应该是,就像我的网站有时为错误提供内容域名,它们是否会因为上述中间件和视图代码中的某些缺陷而发生,或者我应该在其他地方查找?
答案 0 :(得分:5)
我有类似的要求,并决定不使用django网站框架。我的中间件看起来像
class MultiSiteMiddleware(object):
def process_request(self, request):
try:
domain = request.get_host().split(":")[0]
request.site = Site.objects.get(domain=domain)
except Site.DoesNotExist:
return http.HttpResponseNotFound()
然后我的观看次数可以访问request.site
如果您在日志中看到404不属于您的网站,那么似乎有人将其域名指向您的服务器IP地址,您可以使用apache / nginx进行过滤这些在他们点击你的应用程序之前,但你的中间件应该抓住它们(虽然可能通过提出未被捕获的500错误而不是404)
答案 1 :(得分:2)
显然,目标是从一个Django实例服务多个域。这意味着,我们使用相同的模型,相同的数据库,相同的逻辑,相同的视图,相同的模板,但服务于不同的东西。
在搜索互联网时,我想到了使用网站框架。网站框架旨在完成那件事。事实上,网站框架已被用来做到这一点。但我还不知道它是哪个版本的Django,实际上,我认为网站框架只是一个退化模块。基本上,它只是一个具有SITE_ID和SITE_URL的表,您可以使用函数轻松访问它。但是我一直无法找到你可以做多域网站的方法。
所以我的想法是,如何修改url解析器。所有这些背后的想法很简单:www.domain1.com/bar解析为/ domain1 / bar,www.domain2.foo解析为/ domain2 / foo。这解决了这个问题,因为如果您想要提供多个域,您只需要提供多个文件夹。
在Django中,要实现这一点,你必须修改两件事: * Django路由请求的方式 * django写网址的方式
Django使用中间件路由请求。而已。所以我们只需编写一个重新路由请求的中间件。
为了简化操作,中间件可以拥有一个process_request方法,在处理请求之前处理请求(WOW)。所以让我们写一个DomainNameMiddleware
#!python
#app/middleware.py
class DomaineNameMiddleware:
"""
change the request path to add the domain_name at the first
"""
def process_request(self, request):
#first, we split the domain name, and take the part before the extension
request_domain = request.META['HTTP_HOST'].split('.')[-2]
request.path_info = "/%s/%s" % (request_domain, request.path.split('/')[1:])
当我在谈论django编写url时,我主要考虑的是{%url%}模板标记,get_absolute_url方法,resolve和resolve_lazy函数以及那些基本的Django事物。如果我们重写Django处理url的方式,我们必须告诉Django这样写url。
但是基本上它很容易,感谢Django。
您只需重写它们就可以轻松地重写基本的Django功能,通常在您添加为应用程序的模块的 init .py文件中。所以:
#!python
#anyapp/__init__.py
from django.core import urlresolvers
old_reverse = urlresolvers.reverse
def new_reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
"""
return an url with the first folder as a domain name in .com
"""
TLD = 'com'
old_reverse_url = old_reverse(viewname, urlconf, args, kwargs, current_app)
# admin will add itself everytime you reload an admin page, so we have to delete it
if current_app == 'admin':
return '/%s' % old_reverse_url[len('admin'):].replace('adminadmin', 'admin')
return '//%s.%s/%s' % (app, TLD, path)
我将它与base urls.py一起用作调度程序。
#!python
#urls.py
from django.conf.urls import include, url
from domain1 import urls as domain1_urls
from domain2 import urls as domain2_urls
urlpatterns = [
url(r'^domain1/', include(domain1_urls, namespace='domain1')),
url(r'^domain2/', include(domain2_urls, namespace='domain2)),
]
答案 2 :(得分:0)
我建议您使用django-multisite。它将满足您的要求。
答案 3 :(得分:0)
尝试使用django中的“sites”框架来获取域名。我猜你已经知道了。
看看这里:https://docs.djangoproject.com/en/1.7/ref/contrib/sites/#getting-the-current-domain-for-full-urls
见:
>>> Site.objects.get_current().domain
'example.com'
没有https://www
或http://www.
。您的域名可能会在.org
或某个国家.pe
.ru
等结束,而不仅仅是.com
。
有些人可能会出于某种原因没有指向您的域而是指向您的IP地址,可能是开发测试因此您应该始终使用Site.DoesNotExist
答案 4 :(得分:0)
Django的Sites框架有built-in middleware来完成此任务。
只需启用Google协作平台框架并将其添加到您的MIDDLEWARE
:
'django.contrib.sites.middleware.CurrentSiteMiddleware'
每次请求时,这会自动将request
对象传递给Site.objects.get_current()
。它通过让您在每次请求时都能访问request.site
来解决您的问题。
作为参考,code as of 1.11是:
from django.utils.deprecation import MiddlewareMixin
from .shortcuts import get_current_site
class CurrentSiteMiddleware(MiddlewareMixin):
"""
Middleware that sets `site` attribute to request object.
"""
def process_request(self, request):
request.site = get_current_site(request)