简体   繁体   English

Django ManifestStaticFilesStorage + DEBUG = False 在上传的文件中给出错误:他们不显示

[英]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:一切都很顺利:

  1. No issues in collectstatic other than a few missing static files (already solved)除了一些丢失的 static 文件外,collectstatic 没有问题(已经解决)
  2. Static files loaded perfectly Static 文件加载完美

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想法

  • 404 means the file is not there. 404 表示文件不存在。 Guess what?你猜怎么着? it's there, they all are它在那里,它们都在
  • The occasional 500 means permissions.偶尔的 500 表示权限。 Well, I haven't changed the permissions.好吧,我没有更改权限。 Also, permissiones where the same.此外,权限相同。 Also, I'm using WebFaction, it handles all that for me另外,我正在使用 WebFaction,它为我处理所有这些
  • Console in browser says network error.浏览器中的控制台显示网络错误。 In the Network tab it doesn't even show the 404 errors or the few 500 that may appear在“网络”选项卡中,它甚至不显示 404 错误或可能出现的少数 500 个错误
  • Broken DB?损坏的数据库? Nope.没有。 Besides, if it were broken, DEBUG = True would fail此外,如果它被破坏, DEBUG = True将失败
  • Apache error log? Apache 错误日志? Nothing to show for.没有什么可显示的。 The access log shows the access errors, meaning errors on file that are correctly placed访问日志显示访问错误,即正确放置的文件上的错误

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.

相关问题 Django DEBUG=False 不会上传文件到 STATIC_ROOT - Django DEBUG=False won't upload files to STATIC_ROOT 每当django中debug = False时,Heroku会显示Server Error(500),而debug = True no error时 - Whenever debug=False in django, Heroku gives Server Error (500) and when debug=True no error 当生产中的debug = False时,Django在媒体文件上显示404错误 - Django shows 404 error on media files when debug = False in production Django Heroku Debug = False,静态文件导致内部服务器错误 - Django Heroku Debug = False, Static files cause Internal Server Error ckeditor django 没有错误但不显示编辑器 - ckeditor django no error but don't show editor 如果DEBUG = False,则不显示heroku-django上传的图像 - heroku-django-uploaded image is not displayed if DEBUG=False 当 DEBUG=False 时,我的 Django 管理面板给出服务器错误(500) - My Django admin panel gives server error(500) when DEBUG=False Django 只有当 500.html 存在时 Debug 为 False 时,国际化才会给出内部错误 - Django Internationalization gives Internal Error when Debug is False Only when 500.html is present 在Django 1.7上使用Debug False获取Django错误 - Getting Django error with Debug False on django 1.7 Django静态文件未显示在Heroku上 - Django static files don't show up on Heroku
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM