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 Procfile

在heroku上找不到gunicorn

Heroku 上的 Gunicorn 'ImportError: No module named app.wsgiapp'