django多个域名,单个应用程序

时间:2014-09-05 08:44:24

标签: django

我正在尝试将我的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个错误(我有时会在日志中找到它们,在手动浏览我的网站时看不到它们)它们本身不应该是,就像我的网站有时为错误提供内容域名,它们是否会因为上述中间件和视图代码中的某些缺陷而发生,或者我应该在其他地方查找?

5 个答案:

答案 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)

从一个网站(django1.8 python3 +)

提供多个域名

显然,目标是从一个Django实例服务多个域。这意味着,我们使用相同的模型,相同的数据库,相同的逻辑,相同的视图,相同的模板,但服务于不同的东西。

在搜索互联网时,我想到了使用网站框架。网站框架旨在完成那件事。事实上,网站框架已被用来做到这一点。但我还不知道它是哪个版本的Django,实际上,我认为网站框架只是一个退化模块。基本上,它只是一个具有SITE_ID和SITE_URL的表,您可以使用函数轻松访问它。但是我一直无法找到你可以做多域网站的方法。

所以我的想法是,如何修改url解析器。所有这些背后的想法很简单:www.domain1.com/bar解析为/ domain1 / bar,www.domain2.foo解析为/ domain2 / foo。这解决了这个问题,因为如果您想要提供多个域,您只需要提供多个文件夹。

在Django中,要实现这一点,你必须修改两件事: * 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的方式

当我在谈论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://wwwhttp://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)
相关问题