[英]Django ManifestStaticFilesStorage + DEBUG = False gives error in uploaded files: They don't show
I have a problem and I will do the best to explain it, to see if you can help me out.我有一个问题,我会尽力解释它,看看你是否能帮助我。
CONTEXT语境
I have a system running in a test server, which is set up like a production environment in order to test my code before merging to master and give the go to the production server provider of my client to update the code.我有一个在测试服务器中运行的系统,该系统设置为像生产环境一样,以便在合并到 master 之前测试我的代码,并将 go 提供给我的客户端的生产服务器提供商以更新代码。 This means it runs in
DEBUG = False
.这意味着它在
DEBUG = False
中运行。 All good, all perfect for months.一切都好,几个月都完美。
I decided to activate the ManifestStaticFilesStorage
setting in order to have a hash number added in my static files, I've used it before and it's a good way to break cache rules when updating files (like CSS rules that refuse to load). I decided to activate the
ManifestStaticFilesStorage
setting in order to have a hash number added in my static files, I've used it before and it's a good way to break cache rules when updating files (like CSS rules that refuse to load). There is an issue with cache that may be solvable messing around with the server but that's not an option in this case.缓存存在一个问题,可以解决与服务器混淆的问题,但在这种情况下,这不是一个选项。
Everything went smoothly:一切都很顺利:
BUT...但...
THE PROBLEM问题
This system manages content (images, audio files and custom fonts).该系统管理内容(图像、音频文件和自定义字体)。 When I activated the
ManifestStaticFilesStorage
setting, all uploaded files started to throw 404 errors (and some occasional 500 error) in the server access log.当我激活
ManifestStaticFilesStorage
设置时,所有上传的文件都开始在服务器访问日志中抛出 404 错误(偶尔会出现 500 错误)。 Meaning, they look like this:意思是,它们看起来像这样:
You can see the broken image icon but you can also see the background colores of each square (color which is injected by JS because it can be customized in the custom CMS).您可以看到损坏的图像图标,但您也可以看到每个正方形的背景颜色(由 JS 注入的颜色,因为它可以在自定义 CMS 中自定义)。 These images are uploaded in the CMS and they live in the media folder configured in the settings file.
这些图像在 CMS 中上传,它们位于设置文件中配置的媒体文件夹中。
Of course, if I go to DEBUG = True
, everything gets fixed (come on. -.-), I went and recreated production enviroment in local: same issue: DEBUG = False
bad, DEBUG = True
works当然,如果我 go 到
DEBUG = True
,一切都会得到修复(来吧。-.-),我去并在本地重新创建生产环境:同样的问题: DEBUG = False
bad, DEBUG = True
工作
THOUGHTS想法
DEBUG = True
would failDEBUG = True
将失败So, I ran out of ideas.所以,我的想法用完了。 Maybe someone out there has the answer, I hope so.
也许有人在那里有答案,我希望如此。 I will still be trying to solve it but I can use the help, please.
我仍然会尝试解决它,但我可以使用帮助,拜托。
RELEVANT CODE相关代码
storage.py存储.py
class ManifestStaticFilesStorageNotStrict(ManifestStaticFilesStorage):
"""A relaxed implementation of django's ManifestStaticFilesStorage.
"""
manifest_strict = False
settings.py (redacted) settings.py(已编辑)
# -*- coding: utf-8 -*-
# Standard libs imports
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
# Django libs imports
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = <SECRET KEY HERE (: >
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
##########################
# APPLICATION DEFINITION #
##########################
DJANGO_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.sitemaps',
'django.contrib.staticfiles',
]
THIRD_PARTY_APPS = [
# https://github.com/audiolion/django-behaviors
'behaviors.apps.BehaviorsConfig',
# https://github.com/zostera/django-bootstrap4
'bootstrap4',
# https://django-ckeditor.readthedocs.io/en/latest/
'ckeditor',
# https://github.com/praekelt/django-recaptcha
'captcha',
# https://django-tables2.readthedocs.io/en/latest/index.html
'django_tables2',
# https://github.com/django-extensions/django-extensions
'django_extensions',
]
CUSTOM_APPS = [
<CUSTOM APPS HERE (: >
]
ELASTICSEARCH_DSL = {
<ELASTICSEARCH DATA HERE (: >
}
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + CUSTOM_APPS
SITE_ID = 1
AUTH_USER_MODEL = 'users.User'
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# https://github.com/PaesslerAG/django-currentuser
'django_currentuser.middleware.ThreadLocalUserMiddleware',
]
ROOT_URLCONF = 'main.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'main/templates')],
'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',
'main.context_processors.add_to_context',
],
},
},
]
DJANGO_TABLES2_TEMPLATE = 'django_tables2/bootstrap-responsive.html'
WSGI_APPLICATION = 'main.wsgi.application'
LOGIN_URL = reverse_lazy('back_office:auth:login')
SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error']
#####################
# DATABASE SETTINGS #
#####################
#
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
<DATABASE DATA HERE (: >
}
##########################
# AUTHENTICATION BACKEND #
##########################
#
# https://docs.djangoproject.com/en/2.0/topics/auth/customizing/
AUTHENTICATION_BACKENDS = [
<AUTHENTICATION_BACKENDS DATA HERE (: >
]
################################
# PASSWORD VALIDATION SETTINGS #
################################
#
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation'
'.UserAttributeSimilarityValidator',
},
# {
# 'NAME': 'django.contrib.auth.password_validation'
# '.MinimumLengthValidator',
# },
{
'NAME': 'main.validators.password_validators'
'.CustomMinimumLengthValidator',
},
# {
# 'NAME': 'django.contrib.auth.password_validation'
# '.CommonPasswordValidator',
# },
{
'NAME': 'main.validators.password_validators'
'.CustomCommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation'
'.NumericPasswordValidator',
},
]
##################
# GOOGLE ANALYTICS
##################
GOOGLE_ANALYTICS_ID = ""
##################
# EMAIL SETTINGS #
##################
<SETTINGS HERE (: >
#################################
# INTERNATIONALIZATION SETTINGS #
#################################
#
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'es'
LANGUAGES = (
('en', _('English')),
('es', _('Spanish')),
)
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
#############################
# STATIC FILES SETTINGS #
# (CSS, JavaScript, Images) #
#############################
#
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/media')
##############
# RECAPTCHA #
##############
<MORE SETTINGS HERE (: >
################
# FILE STORAGE #
################
#
# This settings is for a custom random number to add to all uploaded
# files in order to break cache
DEFAULT_FILE_STORAGE = 'main.storage.CustomFileSystemStorage'
##################
# LOCAL SETTINGS #
##################
#
# This is the file that contains local configurations like DB passwords,
# keys, user for an API, etc.
#
# This import is done at the end because it will override the default settings
# stablish here.
try:
from .local_settings import * # noqa
except Exception as e:
pass
###################
# CKEDITOR CONFIG #
###################
CKEDITOR_CONFIGS = {
'default': {
# 'skin': 'moono',
'toolbar': 'full',
'skin': 'office2013',
'width': '100%',
}
}
########################
# STATIC FILES STORAGE #
########################
STATICFILES_STORAGE = \
'main.storage.ManifestStaticFilesStorageNotStrict'
local_settings.py (redacted) local_settings.py(已编辑)
# Production settings
DEBUG = False
###################
# ALLOWED DOMAINS #
###################
ALLOWED_HOSTS = [
'localhost',
'localhost:8000',
'127.0.0.1',
'127.0.0.1:8000',
<DOMAIN DATA HERE (: >
]
#############
# DATABASES #
#############
DATABASES = {
<DATABASE DATA HERE (: >
}
################
# STATIC FILES #
################
STATIC_ROOT = '<PATH TO SERVER STATIC FOLDER>'
MEDIA_ROOT = '<PATH TO SERVER STATIC FOLDER>/media'
Thanks in advance.提前致谢。
Well, after hitting my head to the wall a lot, a good night sleep and fresh ideas, I found the problem.好吧,在我的头撞到墙上很多,睡个好觉和新鲜的想法之后,我发现了问题。 It was the silliest thing ever, as usual.
像往常一样,这是有史以来最愚蠢的事情。
If you can see in the settings.py , the MEDIA_URL
is set to /media/
.如果您可以在settings.py中看到,则
MEDIA_URL
设置为/media/
。 Normally, this wouldn't be a problem in an Apache server but in WebFaction, it turned out to be the culprit of my headache.通常,这在 Apache 服务器中不会成为问题,但在 WebFaction 中,结果却是我头痛的罪魁祸首。
For those who don't know, WebFaction obliges you to create apps for everything: Python env, PHP env, Static env, WordPress, Joomla, etc. By creating an app, you have to assing a unique path inside the Website definition, which is a set of apps running under a given domain, so all apps have paths under the same domain and you don't have to modify (in most cases) the httpd.conf
file. For those who don't know, WebFaction obliges you to create apps for everything: Python env, PHP env, Static env, WordPress, Joomla, etc. By creating an app, you have to assing a unique path inside the Website definition, which是在给定域下运行的一组应用程序,因此所有应用程序都具有同一域下的路径,并且您不必修改(在大多数情况下)
httpd.conf
文件。
I have an app for the Django code and another app for the static files, under the domain static/
.我有一个用于 Django 代码的应用程序和另一个用于 static 文件的应用程序,位于域
static/
下。 In the local_settings.py
, you can see that the MEDIA_ROOT
is inside this static path.在
local_settings.py
中,您可以看到MEDIA_ROOT
位于此 static 路径内。
In a regular Apache deploy, you just assign the /media/
URL to the path and that's it.在常规的 Apache 部署中,您只需将
/media/
URL 分配给路径即可。 In WebFaction, given that there is no static app for using the media/
, the MEDIA_URL
variable has to have static/media
as assigned value when switching to DEBUG = False
.在 WebFaction 中,鉴于没有 static 应用程序用于使用
media/
, MEDIA_URL
变量在切换到DEBUG = False
时必须具有static/media
作为分配值。
Just to remember: DEBUG = False
make Django stop serving the static files and leave that entirely to the server where is deployed.请记住:
DEBUG = False
使 Django 停止提供 static 文件并将其完全留给部署的服务器。 So, in DEBUG = True
, it didn't matter which was the media URL because Django is smart enough to see past that.因此,在
DEBUG = True
中,媒体 URL 并不重要,因为 Django 足够聪明,可以看到过去。 But when I made the switch to DEBUG = False
, it naturally failed.但是当我切换到
DEBUG = False
时,它自然而然地失败了。
Silly me, but well, this is how we learn.愚蠢的我,但是,这就是我们学习的方式。
Regards.问候。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.