Skip to main content
 首页 » 编程设计

python之Django、子域和 mod_rewrite。 URL 搞乱了部署设置

2024年09月03日40xxx_UU

我有一个 Django 应用程序正在为(例如)example.com 提供服务。它包含许多子应用程序(例如)strength、speed 和 skill。 URL 方案类似于 http://example.com/strength、http://example.com/speed 和 http://example.com/技能。这就是我运行开发服务器的方式(使用 runserver)并且没有任何问题。

现在,在部署期间,我需要有映射到这些子应用程序的子域。更具体地说,我希望 http://x.example.com 映射到 http://example.com/x (对于 x 的上述值) 然后可以继续处理。

我用谷歌搜索了一下,找到了两种方法。

  • 一个是获取一些中间件来获取 URL 的子域部分并将其保存在传递给我的 View 方法的 request 对象中。然后我在我的应用程序逻辑中完成所有事情。
  • 另一种是使用 Apache mod_rewrite 进行上述 URL 转换,然后让我的应用程序照常运行。

我选择了后者,因为它看起来更整洁,而且我认为我不必在我的核心应用程序中包含特定于部署的代码。

现在,我被一个无法真正找到出路的问题所困扰。在 skill 应用程序中,我有一个命名的 url skill_home。它是 http://example.com/skill。但是,在我部署后,skill_home URL 变为 http://skill.example.com/skill。 Django 将 /skill 附加到顶级域,这就是我得到的。如果我在此 URL 上执行 GET,mod_rewrite 会将其更改为 http://skill.example.com/skill/skill 并且它不起作用。

我的 mod_rewrite 片段看起来像这样

RewriteCond %{HTTP_HOST} !www.example.com$ [NC] 
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC] 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule (.*) /skill/$1  

我该如何巧妙地解决这个问题?

请您参考如下方法:

对于这个答案,我假设您愿意为每个子域执行 mod_rewrite。我认为这不适用于任何 子域(即您提到的 x)。

这将删除领先的 /skill/ 以便您的应用程序将继续工作:

RewriteCond %{HTTP_HOST} !www.example.com$ [NC] 
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC] 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule (/skill/)?(.*) /skill/$2 

更新

好的,所以您要删除链接本身中 URL 的前导部分。

基本上,这意味着您必须编写自定义标签来替换 {% url %} 标签,如下所示:

import re 
from django.template import Library 
from django.template.defaulttags import URLNode, url 
 
register = Library() 
 
class SubdomainURLNode(URLNode): 
    def render(self, context): 
        domain = context['request'].get_host() 
        subdomain = re.sub(r'^www\.','',domain).split('.')[0] 
        path = super(SubdomainURLNode, self).render(context) 
        return re.sub(r'^/%s/' % subdomain, '/', path) 
 
@register.tag 
def subdomainurl(parser, token, node_cls=SubdomainURLNode): 
    """Just like {% url %} but checks for a subdomain.""" 
    node_instance = url(parser, token) 
    return node_cls(view_name=node_instance.view_name, 
        args=node_instance.args, 
        kwargs=node_instance.kwargs, 
        asvar=node_instance.asvar) 

我已经在我的服务器上对此进行了测试,它似乎可以正常工作。