如何使用在Heroku/OpenShift/etc上具有硬编码相对路径的django来提供静态文件?

Dus*_*att 3 django heroku paas

我有第三方提供的HTML/JS/CSS文件(我无法控制),它作为单页面应用程序与使用Django和django-rest-framework构建的后端进行通信.

我想在Heroku上托管这个,因此这些静态资产由Django提供服务.这些文件包含彼此的相对路径.例如,index.html包含:

<link rel="stylesheet" type="text/css" media="screen" href="styles/css/bootstrap.min.css">
Run Code Online (Sandbox Code Playgroud)

这导致404因为styles/css/bootstrap.min.css没有被django路由.

我知道从我的域根目录提供index.html的唯一方法www.domain.com是使用url配置:

url(r'^$', TemplateView.as_view(template_name='index.html'), name='home'),
Run Code Online (Sandbox Code Playgroud)

...即使它不是真正的模板,它只是简单的HTML.

问题出在这样一个事实,即其他资产中的所有网址都与此相关index.html,当然Django不会那样工作.如果我正在开发这个前端应用程序,我将使用static模板标记和各种方法之一来获取javascript的URL.

如果他们提供这个问题的解决方案,我不介意从Heroku切换到另一个PaaS,但手动编辑所有这些文件听起来不是一个有趣的工作...特别是考虑到我将接收这些文件的更新这一事实往前走.

认为在常规旧服务器上解决此问题的方法是配置Web服务器以正确解析这些URL,但Heroku上似乎没有该选项.

met*_*mit 7

以下是如何设置Django来提供静态文件和index.html on/while,同时仍然可以将Django视图用于管理仪表板,注册等.

from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.staticfiles.views import serve
from django.views.generic import RedirectView

admin.autodiscover()

urlpatterns = [

    # / routes to index.html
    url(r'^$', serve,
        kwargs={'path': 'index.html'}),

    # static files (*.css, *.js, *.jpg etc.) served on /
    # (assuming Django uses /static/ and /media/ for static/media urls)
    url(r'^(?!/?static/)(?!/?media/)(?P<path>.*\..*)$',
        RedirectView.as_view(url='/static/%(path)s', permanent=False)),

    # other views still work too
    url(r'^admin/', include(admin.site.urls)),
]
Run Code Online (Sandbox Code Playgroud)

我指定urlpatterns为Django 1.10所需的列表.默认情况下,自1.9以来,重定向不是永久性的,因此您需要明确设置permanent=True是否希望浏览器对此进行缓存,但是在调试时我发现它最好开始False.

这种方法允许您使用诸如create-react-appYeoman前端生成器之类的东西,这些生成器将构建的缩小前端应用程序打包到单个文件夹(如dist /)中.然后,您可以使用脚本将其移动到Django的静态文件文件夹(例如myproject/static /)并从Heroku提供.

Ian写的关于想要为你的静态文件使用S3之类的内容,但有时你只想用一个存储库,一个Heroku dyno开始简单,并且仍然可以使用Django + SPA.此外,使用像WhiteNoise这样的东西可以很好地提供来自Python的静态文件,并允许您以后轻松地将CDN放在静态文件前面.

注意:对于用户上传的文件,您仍应使用Amazon S3或Backblaze B2等外部服务(要集成 4行代码).

提供媒体文件

WhiteNoise不适合提供用户上传的"媒体"文件.首先,如上所述,它仅在启动时检查静态文件,因此将不会看到应用程序启动后添加的文件.更重要的是,从与主应用程序相同的域提供用户上传的文件存在安全风险(Google安全性的这篇博客文章很好地描述了这个问题).除此之外,使用本地磁盘存储和提供用户媒体使得跨多台计算机扩展应用程序变得更加困难.

出于所有这些原因,将文件存储在单独的专用存储服务上并从那里向用户提供服务要好得多.在Django的储存库提供了许多选项,例如亚马逊S3,Azure存储,和Rackspace CloudFiles.

注2:关于生产DEBUG=False问题,请查看WhiteNoise问题以获得解决方案.

注3: 把这个答案到博客文章在这里.

注4:自写这篇文章以来,我一直在为前端路由调整解决方案越来越多,所以我最终发布了一个新的django-spa软件包,适合从Django简单地提供单页应用程序.