Heroku 上的 Django 静态文件
Posted
技术标签:
【中文标题】Heroku 上的 Django 静态文件【英文标题】:Django static files on heroku 【发布时间】:2014-02-04 03:38:34 【问题描述】:我使用“git push heroku master”为heroku部署了一个django应用程序,效果非常好。
然后我使用“heroku create second-app -r staging”在同一个 git 上创建了第二个应用程序
并使用:git push staging master 推送
当我打开第二个应用程序时,没有任何静态文件被拾取或加载(即没有 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',
)
然后我分支了我的代码(所以我有 master 和 staging)并将新的 heroku 远程同步到我的 staging 分支。然后我做了一个 git push staging staging:master ,它做了一个完整的上传;这又一次让我回到了同一个地方...帮助!!!
【问题讨论】:
第二个应用程序也有同样的问题。当我删除第一个并重新提交时,问题就解决了。 【参考方案1】:最终使用我的 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),
)
【讨论】:
请注意,patterns
现在已从 Django 中删除,因此您应该根据以下问题将其他路由附加到现有列表中:***.com/questions/8074955/cannot-import-name-patterns
如果我的项目中没有图片,我需要添加这个吗?【参考方案2】:
我也一直在处理同样的问题。我尝试不使用 David 推荐的解决方案,因为它似乎只用于开发(而不是生产)(参见:Heroku static files not loading, Django)
这是我在代码中更改的两件事。
(我使用的是 Django 1.7)
1) 设置.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 (a) 在您运行“python manage.py collectstatic”时将静态文件放在哪里,以及 (b) 在您运行应用程序时找到静态文件
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)
阅读此处了解有关白噪声的更多信息:https://devcenter.heroku.com/articles/django-assets#whitenoise
另外,记得安装 whitenoise: pip install whitenoise==2.0.6
在部署项目之前,运行: python manage.py collectstatic
这将创建一个由 STATIC_ROOT 指示的文件夹(在您的 settings.py 中声明),其中包含您的所有静态文件。
【讨论】:
【参考方案3】:似乎是因为您使用的是静态文件应用程序而没有设置 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(请注意,我对这个 var 的 conf 可能与您的不同)
然后,推送您的代码并重试。 如果它仍然不起作用,您可以使用它来调试: https://devcenter.heroku.com/articles/django-assets#debugging
【讨论】:
但完全相同的设置文件适用于旧应用程序 - 我只是不明白为什么会有差异? 这很难说,但如果可能的话,我更喜欢明确的事情而不是“它有效,但我不知道为什么”......在出现奇怪的行为后,我决定设置所有变量以防止这种事情。当您使用 PaaS 时,您无法确定它在服务器端做了什么,因此您应该仔细遵循指南。在 Heroku Django 指南示例中,设置了 STATIC_ROOT 和 STATICFILES_DIRS 变量。您应该尝试遵循这一点。 我尝试了你的建议,并在标准 heroku 推送输出中得到了这个 - 但没有区别:-----> 收集静态文件 245 个静态文件已复制。 我还尝试了完全相同的代码副本,该代码第一次在不同的目录、不同的 git 和新应用程序中运行,但仍然失败......有什么想法吗?【参考方案4】:自 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)
【讨论】:
【参考方案5】:对于 Django 2.1.7,为了正常工作,我做了以下更改:
除了 gunicorn
之外,还向 requirements.txt 添加了 whitenoise
项目settings.py
应具有以下内容:
A) 静态设置:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
B) 将whitenoise
添加到中间件:
MIDDLEWARE = [
.....
'whitenoise.middleware.WhiteNoiseMiddleware',
]
最后提交并推送您的更改,然后和平部署您的应用。
【讨论】:
以上是关于Heroku 上的 Django 静态文件的主要内容,如果未能解决你的问题,请参考以下文章
Heroku 上的 Django - 缺少静态文件 manifest.json 文件
如何从 Heroku 上的 Django 项目正确地提供我的 Angular 应用程序静态文件?