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

时间:2014-11-21 16:04:13

标签: 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">

这导致404,因为styles/css/bootstrap.min.css未被django路由。

我知道从我的域根www.domain.com提供index.html的唯一方法是使用以下网址配置:

url(r'^$', TemplateView.as_view(template_name='index.html'), name='home'),

...尽管它不是真正的模板,但它只是简单的HTML。

问题来自于其他资产中的所有网址都与此index.html相关,当然Django不能像这样工作。如果我正在开发这个前端应用程序,我将使用static模板标记以及将URL添加到javascript的各种方法之一。

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

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

2 个答案:

答案 0 :(得分:6)

以下是如何设置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)),
]

我将urlpatterns指定为列表,正如Django 1.10所要求的那样。默认情况下,自1.9以来重定向为not permanent,因此如果您希望浏览器对此进行缓存,则需要显式设置permanent=True,但在调试时我发现最好从False开始。

此方法允许您使用类似create-react-appYeoman前端生成器的内容,将生成的缩小前端应用程序打包到单个文件夹中(如 dist / )。你那么,例如使用脚本将其移动到Django的静态文件文件夹(例如 myproject / static / )并从Heroku提供。

Ian写的关于想要使用S3这样的静态文件的内容,但有时你只想用一个存储库,一个Heroku dyno开始简单,并且仍然可以使用Django + SPA。此外,使用像WhiteNoise之类的东西可以让Python提供静态文件,并且允许你这样做 稍后在easily put a CDN的静态文件前面。

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

  

提供媒体文件

     

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

     

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

注2:关于DEBUG=False的制作有问题,请查看this WhiteNoise issue以获取解决方案。

注3: 将此答案转变为博文here

注意4:自写这篇文章以来,我一直在为前端路由调整解决方案越来越多,所以我最终发布了一个新的django-spa包,适合简单的单一服务来自Django的-page应用程序。

答案 1 :(得分:1)

在Heroku的服务器上存储静态/媒体文件是有问题的,不鼓励。有一些解决方法,但使用替代方法更容易使用这些方法。另外,当dyno重新播放时,Heroku上的文件将被删除。

而是使用Web服务存储文件。这些文件是通过collectstatic(每次推送到Heroku时运行)收集的,这是预期的行为。

为了便于使用和提高性能,您应该从其他来源(如AWS S3)提供静态文件,详见此处 - https://devcenter.heroku.com/articles/s3

这一切意味着您要提供的文件不应该通过您的制作服务器(即您的Heroku dyno)提供,因为它可以提供明显的安全漏洞。相反,您要提供的所有支持文件都应通过其他服务器/位置提供。 Django为此提供了静态文件,当你推送到Heroku时,这些文件(在settings.py中STATICFILES_DIRS中列出的目录中找到的任何文件)都会收集到一个公共位置。

我知道你可能会问&#34;为什么这么复杂????&#34;,这是一个公平的问题,但是一旦你理解了Django处理静态文件的方式,它就会更容易,更有意义。

一篇可能有助于消除困惑的精彩文章。 http://agiliq.com/blog/2014/06/heroku-django-s3-for-serving-media-files/