Heroku 上带有 gunicorn 服务器的 Django 项目不提供静态文件
Posted
技术标签:
【中文标题】Heroku 上带有 gunicorn 服务器的 Django 项目不提供静态文件【英文标题】:Django project with gunicorn server on Heroku does not serve static files 【发布时间】:2012-08-13 04:57:08 【问题描述】:我的 Django 1.3 项目在开发服务器上提供静态文件,但在 gunicorn 服务器上不提供静态文件。我按照this Heroku guide的步骤。
当我像指南中那样使用我的 procfile 的内容时(
web: gunicorn myproject_django.wsgi -b 0.0.0.0:$PORT
) Heroku 无法识别我的项目。
然后我将该 Procfile 更改为:
web: python myproject_django/manage.py run_gunicorn -b 0.0.0.0:$PORT -w 3
现在我的应用程序运行除了静态文件(css 不活动也不图像)。
我的项目树:
.
├── Procfile
├── myproject_django
│ ├── core
│ │ ├── admin.py
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── base.css
│ │ │ │ ├── layout.css
│ │ │ │
│ │ │ └── media
│ │ │ ├── pek.ico
│ │ │ ├── pek.png
│ │ │ ├── pek_symbol.png
│ │ ├── tests.py
│ │ └── views.py
│ ├── __init__.py
│ ├── manage.py
│ ├── settings.py
│ ├── templates
│ │ └── core
│ │ ├── home.html
│ │ └── install.html
│ └── urls.py
└── requirements.txt
settings.py 的潜在相关部分
MEDIA_ROOT = ''
MEDIA_URL = '/static/media'
STATIC_ROOT = ''
STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = '/static/admin/'
STATICFILES_DIRS = (
os.path.abspath(__file__)+'/..'+'/myproject_django/core/static',
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'core',
'gunicorn',
'django.contrib.admin',
)
编辑
Francis Yaconiello 进入后我调整了以下内容:
在 settings.py 中
STATIC_ROOT = os.path.join(os.getcwd(),'core/static')
STATICFILES_DIRS = ( os.path.abspath(__file__)+'/..'+'/core/static', )
在 gitignore 中:
staticfiles/*
然后提交。
最后跑了heroku run python myproject_django/manage.py collectstatic
。
但是当我检查网页时仍然没有提供静态文件。 鉴于我的目录树,为什么这些更改不起作用?
编辑2
我仍然看不到我的静态文件。当我在DEBUG=True
时单击图像时,我得到了这个:
Request URL: http://myproject.herokuapp.com/static/media/pek.png
树(注意staticfiles
目录为空)
.
├── Procfile
├── myproject_django
│ ├── admin
│ ├── core
│ │ ├── admin.py
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── base.css
│ │ │ │ ├── layout.css
│ │ │ └── media
| | | ├── pek.ico
| │ │ ├── pek.png
| │ │ ├── pek_symbol.png
│ │ ├── tests.py
│ │ ├── views.py
│ ├── __init__.py
│ ├── manage.py
│ ├── settings.py
│ ├── staticfiles
│ ├── templates
│ │ └── core
│ │ ├── 404.html
│ │ ├── 500.html
│ │ ├── home.html
│ │ └── install.html
│ ├── urls.py
└── requirements.txt
在 settings.py 中
PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'static/media')
STATIC_ROOT = os.path.join(PROJECT_PATH,'staticfiles')
STATICFILES_DIRS = (
os.path.join(PROJECT_PATH, 'core/static'),
)
【问题讨论】:
【参考方案1】:指定您的STATIC_ROOT
我一般设置为:
import os
STATIC_ROOT = os.path.join(os.getcwd(), "staticfiles")
在您的项目中创建该目录
mkdir staticfiles
确保静态文件的内容未被 git 跟踪
nano .gitignore
添加
staticfiles/*
然后提交并推送到heroku。
最后,
heroku run python manage.py collectstatic
编辑
STATIC_ROOT = os.path.join(os.getcwd(),'core/static')
STATICFILES_DIRS = ( os.path.abspath(__file__)+'/..'+'/core/static', )
这两个设置不能是一回事。
STATICFILES_DIR
可以,如果多余的话,你的STATICFILES_FINDERS
已经告诉它在每个应用程序的static
目录中查找静态文件:'django.contrib.staticfiles.finders.AppDirectoriesFinder',
STATIC_ROOT
的目的是提供一个与您的项目完全分离的新目录,您可以使用像 nginx 这样的第三方服务器提供服务。这就是您创建该目录的原因staticfiles
:
STATIC_ROOT = os.path.join(os.getcwd(),'staticfiles')
另一个编辑
临时文件系统的解决方法
每个 dyno 都有自己的临时文件系统,以及最近部署的代码的新副本。在 dyno 的生命周期中,它的运行进程可以将文件系统用作临时暂存器,但任何其他 dyno 中的进程都看不到写入的文件,并且在停止或重新启动 dyno 时,任何写入的文件都将被丢弃。
这意味着只要你在 web 启动期间在每个 dyno 实例上收集静态,你就不会有任何问题。
web: python myproject_django/manage.py collectstatic --noinput; python myproject_django/manage.py run_gunicorn -b 0.0.0.0:$PORT -w 3
也就是说,我目前使用 S3 和 django 存储 http://django-storages.readthedocs.org/en/latest/index.html。这很容易(而且便宜)。
【讨论】:
你回答后我改了一些东西,你能检查一下原帖的编辑吗? 再看一遍,我加了一些解释。 一旦你改变了你的 STATIC_ROOT 你是heroku run python manage.py collectstatic
吗?你能添加 collectstatic 的输出吗?
不适用于heroku,参见。 ephemeral filesystem,也刚刚回答了@Bentley4 的另一个问题***.com/a/12014658/343834
过去,我在 web worker 启动过程中运行 collectstatic(在 procfile 中),所以每当 webworker 启动或重新启动时,它都会收集我的静态文件,这样我就不会因为临时文件系统而感到不便.我实际上会推荐 S3 和 django storages 应用程序(使用 S3 Boto)来解决这个问题。【参考方案2】:
只有一种解决方案。
在 urls.py 中添加:
from django.conf import settings
urlpatterns += patterns('',
(r'^static/(?P<path>.*)$', 'django.views.static.serve', 'document_root': settings.STATIC_ROOT),
)
附言对于STATIC_URL = '/static/'
【讨论】:
【参考方案3】:使用作为heroku-django-cookbook 提供的post_compile
的一部分运行的run_collectstatic
脚本。它利用了 Heroku python buildpack 提供的 post_compile
钩子
【讨论】:
【参考方案4】:我遇到了同样的问题;看来您特别需要这三个设置:
STATIC_ROOT
必须在您的settings.py
中定义,例如:
STATIC_ROOT = os.path.join(PROJECT_PATH, 'served/static/')
其中PROJECT_PATH
是您的项目根目录(在您的情况下,是myproject_django
目录的绝对路径。
同样,STATIC_URL
也必须设置(如果你不这样做,Django 无论如何都会抛出一个 ImproperlyConfigured 错误)。您当前的'/static/'
设置很好。
在你的根urls.py
,配置静态url:
from django.conf import settings
from django.conf.urls.static import static
...
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
最后,运行python manage.py collectstatic
;这会将所有文件从/path/to/site-packages/django/contrib/admin/static/admin/
复制到/served/static/
。 (您可以阅读更多关于 Django 如何提供静态文件的信息 here)。
现在,当您运行 foreman start
时,您应该会看到带有样式的管理员。
不要忘记将served/static/
添加到您的.gitignore
!
【讨论】:
【参考方案5】:我找到了 here 解决我在 heroku 上使用 Django 的所有问题的好方法
【讨论】:
以上是关于Heroku 上带有 gunicorn 服务器的 Django 项目不提供静态文件的主要内容,如果未能解决你的问题,请参考以下文章
部署到 Heroku 时,如何在 Procfile 中导入带有 Gunicorn 的自定义模块?
在 Heroku 上为 Django 配置 gunicorn
如何调试使用 whitenoise、gunicorn 和 heroku 服务的 django 静态文件?
Heroku 上的 Gunicorn 'ImportError: No module named app.wsgiapp'