如何在文件夹结构中为Django重写URL

时间:2019-05-10 21:15:01

标签: python django nginx url-rewriting

我有我的Django应用,并且有以下用例:

  1. 本地发展。由于我的应用程序非常简单,因此我喜欢通常的manage.py runserver方法。因此,我希望我的应用可以在这种情况下正常工作。
  2. 生产环境。我们有一个Web服务器并在不同的URL下托管工具,例如https://myserver.com/tool1https://myserver.com/tool2等。因此,我想将我的应用程序置于这种结构中
  3. (理论上)除了用例2外,我可能希望将应用托管在其自己的域下,例如https://tool.myserver.com

但是当我尝试执行此操作时,我遇到了静态文件问题(叹气!),因为如果我将STATIC_URL作为相对路径STATIC_URL='static/',则它不适用于“嵌套”页面(即,如果我在myserver.com/tool1/page上,则静态URL将映射到myserver.com/tool1/page/static,这是不正确的)。 另一方面,如果我使用绝对路径STATIC_URL='/static/',那么它对于情况2根本不起作用,因为Django应用程序不知道URL所在的/tool1部分。

根据环境和硬编码STATIC_URL,我可以为STATIC_URL='/tool1/static/'使用两个不同的变体,但是对于情况3,相同的代码将不起作用...

我应该如何处理这种情况?

3 个答案:

答案 0 :(得分:1)

从Django应用程序处理STATIC_URL可能会导致开销。由于您有多个子目录,为什么不只从其中一个提供静态文件呢?提供静态文件时,不必与子目录匹配。

让我们说,如果您这样设置STATIC_URL

STATIC_URL = "/tool1/static/"

然后,您可以像这样配置NGINX

server {
    listen 80

    server_name *.myserver.com;

    location /tool1/static/ {
        root /path/to/STATIC_ROOT;
    }

    location / {
        proxy_pass http://localhost:8000;  # <-- No trailing slash to make it work with gunicorn
    }

    location /tool2/ {
        proxy_pass http://localhost:8000;
        proxy_set_header SCRIPT_NAME /tool2;  # <-- For serving in sub path
    }

    location /tool1/ {
        proxy_pass http://localhost:8000;
        proxy_set_header SCRIPT_NAME /tool1; # <-- For serving in sub path
    }

}

然后在设置中将STATIC_URL更新为/tool1/static/。另外,请确保您的STATIC_ROOT指向服务器中静态文件所在的正确路径。最后,在部署静态文件之前,您需要运行collectstatic command将静态文件放入STATIC_ROOT目录中,然后重新启动NGINX服务器。

更新:不建议使用硬编码的网址。相反,在模板中,您应该使用{% URL '<url_name> '%}标签,或者在python代码中使用reverse()。因此,django将自行解析网址。当它位于/tool1位置时,URL将解析为/tool1/url_name/,而当您处于位置/tool2/url_name(基于/tool2)时,URL将被解析为SCRIPT_NAME

答案 1 :(得分:0)

我建议将您的静态文件放在存储服务中,例如AWS S3,Google Cloud Storage等。 这样,无论您使用哪种网址(嵌套,子域等等),它都始终可用

示例设置(可能需要更多步骤):

  • 更改您的settings.py

    STATIC_URL = 'https://storage.googleapis.com/your_bucket/static/'

    STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

    STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)

  • 在部署应用程序之前,运行manage.py collectstatic --noinput

  • staticfiles文件夹中的文件复制到存储服务,并确保它们是公开的
  • 部署您的应用

我发现whitenoise确实可以帮助静态文件大小和更容易部署

答案 2 :(得分:0)

似乎没有真正好的解决方法。但是,我发现了几种选择:

始终使用一个规范地址(个人首选)

我应该问自己“为什么要在https://myserver.com/tool1https://tool1.myserver.com上都可以使用您的工具?”。实际上,我没有任何理由为什么要同时单独提供。因此,只需选择“规范”地址并设置适当的重定向:

如果域是规范的:

    server_name myserver.com
    location /tool1/ {
            rewrite ^/tool1/?(.*)$ https://tool1.myserver.com/$1 permanent;
    }

如果文件夹是规范的:

    server_name tool1.myserver.com
    location / {
            rewrite ^ https://myserver.com/tool1$request_uri? permanent;
    }

然后在后端使用与规范地址相对应的STATIC_URL的 one 选项(即/static用于子域,/tool1/static用于文件夹)

其他标题或URL参数

如果有理由(告诉我为什么!)不使用重定向并且同时使用两个地址,则如ruddra所述,可以添加其他标头,然后在后端使用它们以生成稍微不同的页面:

location /tool1/ {
    <proxy_pass something>
    proxy_set_header SCRIPT_NAME /tool1;
}

如果您选择文件夹作为规范地址,则可以使用相同的方法,那么您可能要避免在后端对tool1进行硬编码。然后,也许您可​​以使用自定义标头或可以在后端处理的其他url参数,例如?from=domain [1]。在这里我没有现成的解决方案,因为对我而言首选子域大小写。

相关问题