将 Django 应用部署到 Heroku 时,执行 Collectstatic 操作出现错误

86

我正在尝试将Django应用程序部署到Heroku,它开始构建、下载和安装所有内容,但是当它来到收集静态文件时,我得到了以下的结果:

$ python manage.py collectstatic --noinput
remote:        Traceback (most recent call last):
remote:          File "manage.py", line 10, in <module>
remote:            execute_from_command_line(sys.argv)
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
remote:            utility.execute()
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
remote:            self.fetch_command(subcommand).run_from_argv(self.argv)
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/base.py", line 390, in run_from_argv
remote:            self.execute(*args, **cmd_options)
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/base.py", line 441, in execute
remote:            output = self.handle(*args, **options)
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 168, in handle
remote:            collected = self.collect()
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 98, in collect
remote:            for path, storage in finder.list(self.ignore_patterns):
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/contrib/staticfiles/finders.py", line 112, in list
remote:            for path in utils.get_files(storage, ignore_patterns):
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/contrib/staticfiles/utils.py", line 28, in get_files
remote:            directories, files = storage.listdir(location)
remote:          File "/app/.heroku/python/lib/python2.7/site-packages/django/core/files/storage.py", line 300, in listdir
remote:            for entry in os.listdir(path):
remote:        OSError: [Errno 2] No such file or directory: '/app/blogproject/static'
remote: 
remote:  !     Error while running '$ python manage.py collectstatic --noinput'.
remote:        See traceback above for details.
remote: 
remote:        You may need to update application code to resolve this error.
remote:        Or, you can disable collectstatic for this application:
remote: 
remote:           $ heroku config:set DISABLE_COLLECTSTATIC=1
remote: 
remote:        https://devcenter.heroku.com/articles/django-assets
remote: 
remote:  !     Push rejected, failed to compile Python app
remote: 
remote: Verifying deploy...
remote: 
remote: !   Push rejected to pin-a-voyage.

这是整个settings.py文件

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import dj_database_url

BASE_DIR = os.path.dirname(os.path.dirname(__file__))
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))



# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '*********************'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True


# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
    'custom_user',
    'django_markdown',
    'parsley',
)

#### AUTH ###

AUTH_USER_MODEL = 'custom_user.CustomUser'

AUTHENTICATION_BACKENDS = (
    'custom_user.backends.CustomUserAuth',
    'django.contrib.auth.backends.ModelBackend',
    # 'django.contrib.auth.backends.RemoteUserBackend',
)

#############

#### EMAIL ###

EMAIL_USE_TLS = True
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_PASSWORD = '***' #my gmail password
EMAIL_HOST_USER = 'voyage.pin@gmail.com' #my gmail username
DEFAULT_FROM_EMAIL = 'voyage.pin@gmail.com'
SERVER_EMAIL = 'voyage.pin@gmail.com'
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

##############

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

ROOT_URLCONF = 'blogproject.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'blogproject.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'blogproject',
        'USER': '***',
        'PASSWORD': '***',
        'HOST': 'localhost',
        'PORT': '',
    }
}


# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Update database configuration with $DATABASE_URL.
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers
ALLOWED_HOSTS = ['*']

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'

# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
    os.path.join(PROJECT_ROOT, 'static'),
)

# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

这是项目的结构。
blog-project -- blog -- migrations
                     -- static
                     -- templates
             -- blogproject
             -- blogprojectenv
             -- custom_user
             -- media
             -- .git

有什么想法吗?
21个回答

101

我今天刚更新到Django 1.10,遇到了完全相同的问题。你的静态设置与我的也完全一样。

以下操作适用于我,可以尝试一下:

  1. 在部署时禁用collectstatic

    heroku config:set DISABLE_COLLECTSTATIC=1

  2. 部署

    git push heroku master

  3. 运行迁移(django 1.10 至少添加了一个)

    heroku run python manage.py migrate

  4. 使用bower运行collectstatic

    heroku run 'bower install --config.interactive=false;grunt prep;python manage.py collectstatic --noinput'

  5. 为未来的部署启用collecstatic

    heroku config:unset DISABLE_COLLECTSTATIC

  6. 自己尝试(可选)

    heroku run python manage.py collectstatic

未来的部署现在应该像往常一样工作了。


1
在我的情况下,我需要修复一些与 python manage.py collectstatic 相关的错误,因此 DISABLE_COLLECTSTATIC 只是一个权宜之计... - citynorman
1
不知道为什么这个有效,但它解决了我的问题,所以+1。 - waqasgard
1
当我运行 heroku config:set DISABLE_COLLECTSTATIC=1 时,我得到了以下错误信息: › Error: Missing required flag:
› -a, --app APP app to run command against › See more help with --help
- Ali Husham
3
"bower" 和任何事情有什么关系啊? - blimpse
3
收到错误信息 bash: bower: command not found - Alexander P
显示剩余2条评论

42
你已经将 STATICFILES_DIRS 配置为期望与你的 settings.py 文件在同一目录下存在一个名为 static 的文件夹,所以请确保它存在于那个位置而不是其他地方。
此外,你在那个 static 文件夹中有任何文件吗?如果没有,则 git 不会跟踪它,因此尽管它在本地存在,但它在 git 中不存在。解决这个问题的通常方法是在该目录中创建一个名为 .keep 的空文件,这将确保 git 跟踪它。但是一旦在此目录中有一些静态文件,则不再是问题。

这对我有用,因为在我的Django应用程序中,我的project包中实际上有一个空的静态目录,因为所有的静态文件都在主app包内的静态目录中。 - AdjunctProfessorFalcon
我完全忽略了/static,所以它根本没有添加。谢谢,要不是你,我可能永远都想不到这个问题。 - TrialAndError
谢谢,将某些东西放入静态文件夹后问题解决了。 - NIKHIL CHANDRA ROY
非常感谢。我创建了静态目录并向其中添加了一个文件夹和一个空文件,现在它可以正常工作了。 - AfriPwincess
这帮助解决了我的问题。谢谢大家。 - DevAdedoyin
显示剩余2条评论

24

不要使用heroku config:set DISABLE_COLLECTSTATIC=1禁用Heroku上的collectstatic。这只会隐藏错误,而不会使您的应用程序变得健康。

相反,更好的方法是了解为什么collectstatic命令失败,因为这意味着您的设置存在问题。

步骤1

在本地运行这两个命令:

python manage.py collectstatic
python manage.py test

您应该会看到一个或多个错误信息。大部分情况下,这是因为缺少某个变量(例如:STATIC_ROOT),您需要将其添加到您的项目的settings.py文件中。

必须添加test命令,因为一些与collectstatic相关的问题只会通过test浮出水面,例如此问题

步骤2

一旦您在本地修复了所有错误消息,再次推送到heroku。

故障排除

请记住,您还可以在heroku虚拟机中直接运行命令。 如果无法在本地重现,请在heroku中运行collecstatic命令,并直接检查您的生产环境中发生了什么:

python manage.py collectstatic --dry-run --noinput

启动Heroku虚拟机

(同样适用于Heroku控制台)


我在执行第一步后没有任何错误,但是Git仍然无法推送? - CountDOOKU
这是正确的,不要禁用该命令,在我的情况下,我只需要编辑 settings.py 文件,通过添加 STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 来指定静态文件文件夹的位置,所以现在当命令在服务器上运行时,我没有任何问题。 - jadinerky

7

在本地运行python manage.py collectstatic并修复任何错误。在我的情况下,有引用错误导致该命令无法成功运行。


作为一个附注,使用whitenoise和debug=False在heroku上提供静态文件最终变得一团糟,我经过两天的折腾也无法使其正常工作。最终,我使用aws s3+cloudfront设置了静态文件,并将“STATIC_URL='https://xxxxxxxxxxxxxx.cloudfront.net'”进行配置,现在它完美地运行。 - citynorman

6
如果您使用django-heroku库,可能会忘记在settings.py文件的底部加入此设置,以便能够读取所有配置参数。
import django_heroku

django_heroku.settings(locals())

文档一样:

Django-Heroku的用法

settings.py文件中,最底部:

# Configure Django App for Heroku.
import django_heroku
django_heroku.settings(locals())

这将自动为您的应用程序配置 DATABASE_URLALLOWED_HOSTS、WhiteNoise(用于静态资源)、日志记录以及 Heroku CI。
附言:抱歉我的英语不好。

5
这对我有效:
步骤1 - heroku config:set DISABLE_COLLECTSTATIC=1 步骤2 - git push heroku master

你打错字了:我认为应该是 heroku config:set DISABLE_COLLECTSTATIC=1。 - Kjell

5
  • 出现此错误是因为您的项目根目录中没有 staticfiles 文件夹。

  • 别担心,解决方法很简单

  • 您只需要两个步骤

步骤 1:打开您的 settings.py 文件并添加以下内容:

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

STATIC_ROOT = BASE_DIR / 'staticfiles'
步骤二:在您的项目根目录下,终端中运行以下命令。 (如果您正在使用Django项目的任何虚拟环境,则进入您的虚拟环境,然后进入您的项目根目录,然后运行以下给定的命令。)
python manage.py collectstatic

恭喜您:您的问题已解决。
现在,您可以提交并推送您的"更改",以便其在您的存储库中反映出来,然后您就可以继续进行了。

对我没有起作用。 - CountDOOKU

4

我遇到了同样的问题...

按照以下步骤操作:

  1. heroku config:set DISABLE_COLLECTSTATIC=1
  2. git push heroku master
  3. python manage.py collectstatic
  4. python manage.py test
  5. 如果在运行测试后出现任何错误,请检查您的 STATIC_ROOT 是否正确,像这样 ==> STATIC_ROOT = os.path.join(BASE_DIR, 'static')
  6. 运行collectstatic命令后,请检查所有静态文件是否存储在根目录下的static目录中(与manage.py同级)...
  7. heroku run python manage.py collectstatic.
  8. heroku run python manage.py migrate
  9. heroku config:unset DISABLE_COLLECTSTATIC (供将来使用)。

2

Heroku已经提供了一份文件,其中包含有关如何处理此问题的建议。你可以在这里找到:https://devcenter.heroku.com/articles/django-assets

将以下内容添加到settings.py中:


"最初的回答"
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

在您的项目根目录下创建一个名为staticfiles的目录,将网站图标或其他文件放入其中,并确保git跟踪它。然后在Heroku上执行collectstatic命令即可完成操作。 "最初的回答"

1
尝试重新部署应用程序后遇到了这个问题。在我指定以下命令后,问题得到了解决。
$ heroku config:set SECRET_KEY="*secret_key*"
$ heroku config:set DEBUG_VALUE="True"
$ heroku config:set EMAIL_USER="*user-email*"
$ heroku config:set EMAIL_PASS="*pass*"

这些在settings.py中的变量使用了本地环境变量,而Heroku环境中没有这些变量,因此出现了错误。

这是一个有帮助的答案。像下面某个回答中提到的那样,禁用COLLECTSTATIC是一种解决方法。我发现对于我的情况,我没有在Heroku上设置SECRET_KEY配置变量,一旦我设置好了,一切都正常了。 - The Sammie
这样做不会在生产环境中启用 DEBUG,这是绝对不可以的。应该将其设置为 false。 - wjh18

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接