在Heroku上使用Django静态文件

19

我使用"git push heroku master"将一个Django应用部署到了Heroku,这一步非常顺利。

接着,我在同一个Git仓库创建了一个名为"second-app"的第二个应用,并执行了以下操作:"heroku create second-app -r staging"

然后使用"git push staging master"进行推送。

但是当我打开"second-app"时,静态文件没有被识别或加载(例如CSS、JS或图像都未能正常工作)。

这让我感到非常困惑——请帮忙解决!

下面是我的设置文件:

import os
import platform
import dj_database_url

DEBUG = True
TEMPLATE_DEBUG = DEBUG

# This should work for any deployment
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))

ADMINS = (
    ('me', 'me@gmailcom'),
)

MANAGERS = ADMINS
# LOCAL SETTINGS
if platform.system() in ['Windows', 'Darwin']:
    #EV = 'LOCAL'
    DATABASES = {
             'default': {
                 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
                 'NAME': BASE_DIR + '//db//db.sqlite3',
                 'USER': '',                      # Not used with sqlite3.
                 'PASSWORD': '',                  # Not used with sqlite3.
                 'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
                 'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
             }
    }
    # Hosts/domain names that are valid for this site; required if DEBUG is False
    # See https://docs.djangoproject.com/en/1.4/ref/settings/#allowed-hosts
    ALLOWED_HOSTS = []

    CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
        'TIMEOUT': 86400,
        'OPTIONS': {
            'MAX_ENTRIES': 10000
            },
        }
    }

# HEROKU SETTINGS
else:
    #EV = 'HEROKU'
    # DEBUG = False
    DATABASES = {}
    DATABASES['default'] =  dj_database_url.config()

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

    # Hosts/domain names that are valid for this site; required if DEBUG is False
    # See https://docs.djangoproject.com/en/1.4/ref/settings/#allowed-hosts
    # Allow all host headers
    ALLOWED_HOSTS = ['*']

    # Todo: ammar - update to Memcached
    CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
        'TIMEOUT': 86400,
        'OPTIONS': {'MAX_ENTRIES': 10000},
        }
    }

TIME_ZONE = 'Europe/London'

LANGUAGE_CODE = 'en-gb'

SITE_ID = 1

USE_I18N = True

USE_L10N = True

USE_TZ = False

MEDIA_ROOT = ''

MEDIA_URL = '/media/'

STATIC_ROOT = ''

STATIC_URL = '/static/'


STATICFILES_DIRS = ()

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)


SECRET_KEY = '***'

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
#     'django.template.loaders.eggs.Loader',

)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'sm.urls'

# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'sm.wsgi.application'

TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, 'mytemplates')
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    'django.contrib.admindocs',
    'smcore',
    'south',
    'django.contrib.humanize',
)



LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/getStarted/'
LOGOUT_URL = '/do_logout/'

# e-mail server
EMAIL_HOST_USER = '***@gmail.com'
EMAIL_HOST= 'smtp.gmail.com'
# EMAIL_PORT = 465
EMAIL_USE_TLS = True
EMAIL_HOST_PASSWORD = '***'
DEFAULT_FROM_EMAIL = '***@gmail.com'
SERVER_EMAIL = '***@gmail.com'

更新

我复制了代码并重新部署,通过对设置进行以下更新,成功地运行了:

STATIC_ROOT = 'staticfiles'

STATIC_URL = '/static/'

STATICFILES_DIRS = (
    (os.path.join(BASE_DIR,'smcore','static')),
)


STATICFILES_FINDERS = (

    #'django.contrib.staticfiles.finders.FileSystemFinder',
    #'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    #'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

我之后分支了我的代码(现在有主分支和 staging 分支),并将新的 heroku 远程同步到我的 staging 分支。然后我执行了 git push staging staging:master 命令,它做了一个完整的上传;结果让我又回到了原来的地方... 救命啊!!!


我也遇到了第二个应用程序的同样问题。当我删除第一个并重新提交后,问题得到了解决。 - g.a
5个回答

18

最终我在我的urls文件中使用以下代码解决了这个问题 - 参考自这个问题:Heroku - Handling static files in Django app

from <app> import settings
urlpatterns += patterns('',
        (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
    )

1
请注意,Django现已删除patterns,因此您应该根据此问题(https://dev59.com/C2sz5IYBdhLWcg3wLEu9)将其他路由附加到现有列表中。 - Charlie Weems
如果我的项目中没有图片,我需要添加这个吗? - Lord-shiv

9
我也遇到了同样的问题。我尝试不使用David推荐的解决方案,因为它似乎仅用于开发环境而不是生产环境(参见:Heroku静态文件未加载,Django)。
以下是我在代码中更改的两个事项。
(我正在使用Django 1.7)
1)settings.py
我向设置文件添加了这些行
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
TEMPLATE_DIRS = (
    os.path.join(BASE_DIR,  'templates'),
    # Add to this list all the locations containing your static files 
)

STATIC_ROOT:这告诉Django在运行“python manage.py collectstatic”时将静态文件放置在哪里,以及在运行应用程序时查找静态文件的位置。

TEMPLATE_DIRS:这告诉Django在搜索静态文件时从哪里查找您的静态文件,当您运行“python manage.py collectstatic”时。

2)wsgi.py

我的文件最初是:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xxxx.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

我把它改成了:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xxxx.settings")

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise
application = get_wsgi_application()
application = DjangoWhiteNoise(application)

阅读此处以获取有关whitenoise的更多信息:https://devcenter.heroku.com/articles/django-assets#whitenoise


另外,请记得安装whitenoise: pip install whitenoise==2.0.6

在部署项目之前,运行: python manage.py collectstatic

这将创建一个由STATIC_ROOT(在settings.py中声明)指示的文件夹,其中包含所有静态文件。


4
似乎是因为你使用了staticfiles应用程序,但没有设置STATIC_ROOT选项。
相比之下,我的settings.py文件如下:
# Static asset configuration
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, '../myapp/static')

你还应该设置STATICFILES_DIRS(请注意,我这个变量的配置可能与你的不同)

然后,推送你的代码并再次尝试。 如果仍然不起作用,你可以使用以下方法进行调试: https://devcenter.heroku.com/articles/django-assets#debugging


但是完全相同的设置文件适用于旧应用程序 - 我只是不明白为什么会有差异? - Ammar Akhtar
很难说,但如果有可能,我更喜欢明确的事情,而不是“它能运行,但我不知道为什么”...在遇到奇怪的行为之后,我决定设置所有变量以防止这种事情发生。由于您正在使用PaaS,所以无法确定服务器端执行了什么操作,因此您应该仔细遵循指南。在Heroku Django指南示例中,已设置STATIC_ROOT和STATICFILES_DIRS变量。您应该尝试遵循这个设置。 - David Dahan
我尝试了你建议的方法,并在标准的Heroku推送输出中得到了这个结果 - 但没有任何区别: -----> 收集静态文件 复制了245个静态文件。 - Ammar Akhtar
我也尝试了一份完全相同的代码副本,它在不同的目录、不同的Git和新应用程序中第一次运行就成功了,但仍然失败了...有什么想法吗? - Ammar Akhtar

2
自Django 1.3起,您可以执行以下操作:
# only showing relevant imports
from django.conf import settings
from django.conf.urls.static import static


urlpatterns = patterns(
    '',

    # your urls go here
)

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL,
                          document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)

2

为了让Django 2.1.7正常工作,我进行了以下更改:

  1. Added whitenoise to requirements.txt in addition to gunicorn

  2. Project settings.py should have the following:

    A) static settings:

    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, "static"), 
    ]
    

    B) Add whitenoise to middleware:

    MIDDLEWARE = [
       .....
       'whitenoise.middleware.WhiteNoiseMiddleware',
    ]
    
最后提交并推送你的更改,然后平静地部署你的应用程序。

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