Django collectstatic未收集静态文件问题求助
Django静态文件收集问题排查与解决
问题描述
从GitHub克隆项目到本地后,执行collectstatic命令时,静态文件未被复制到staticfiles目录。运行全路径查找命令:
python manage.py findstatic D:\web_proyects\imprenta_gallito\static\css\home.css
触发错误:
django.core.exceptions.SuspiciousFileOperation: The joined path (D:\web_proyects\imprenta_gallito\static\css\home.css) is located outside of the base path component (D:\virtual_envs\imprenta_gallito\Lib\site-packages\django\contrib\admin\static)
项目settings.py配置如下:
import os import os import secrets from pathlib import Path import dj_database_url from decouple import config # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = os.environ.get( "SECRET_KEY", default=secrets.token_urlsafe(nbytes=64), ) IS_HEROKU_APP = "DYNO" in os.environ and not "CI" in os.environ if not IS_HEROKU_APP: DEBUG = True if IS_HEROKU_APP: ALLOWED_HOSTS = ["*"] else: ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ "whitenoise.runserver_nostatic", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", 'shop', 'search_app', 'cart', 'order', 'marketing', 'django.contrib.humanize', 'crispy_forms', 'crispy_bootstrap4' ] MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware", "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", ] ROOT_URLCONF = 'imprenta_gallito.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'shop', 'templates/'), os.path.join(BASE_DIR, 'search_app', 'templates/'), os.path.join(BASE_DIR, 'cart', 'templates/'), os.path.join(BASE_DIR, 'order', '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', 'shop.context_processor.menu_links', 'shop.context_processor.has_shop', 'cart.context_processor.cart_items_counter' ], }, }, ] WSGI_APPLICATION = 'imprenta_gallito.wsgi.application' # Database if IS_HEROKU_APP: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': config('HEROKU_POSTGRESQL_NAME'), 'USER': config('HEROKU_POSTGRESQL_USER'), 'PASSWORD': config('HEROKU_POSTGRESQL_PASSWORD'), 'HOST': config('HEROKU_POSTGRESQL_HOST'), 'PORT': config('HEROKU_POSTGRESQL_PORT'), } } else: SECURE_SSL_REDIRECT = False DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", } } AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] LANGUAGE_CODE = 'es-PE' TIME_ZONE = 'UTC' USE_THOUSAND_SEPARATOR = True USE_TZ = True # Static files configuration STATIC_ROOT = BASE_DIR / "staticfiles" STATIC_URL = "static/" STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "whitenoise.storage.CompressedStaticFilesStorage", }, } WHITENOISE_KEEP_ONLY_HASHED_FILES = True DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'static', 'media') CRISPY_TEMPLATE_PACK = 'bootstrap4' AWS_S3_OBJECT_PARAMETERS = { 'Expires': 'Thu, 31 Dec 2099 20:00:00 GMT', 'CacheControl': 'max-age=94608000', } ### MAILGUN - EMAIL MESSAGE SETTINGS ### EMAIL_HOST = os.environ['EMAIL_HOST'] EMAIL_PORT = os.environ['EMAIL_PORT'] EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=True, cast=bool) EMAIL_HOST_USER = os.environ['EMAIL_HOST_USER'] EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD'] SECURE_BROWSER_XSS_FILTER = True X_FRAME_OPTIONS = 'DENY' PACKS3X2 = os.environ['PACKS3X2'] LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format': ('%(asctime)s [%(process)d] [%(levelname)s] ' + 'pathname=%(pathname)s lineno=%(lineno)s ' + 'funcname=%(funcName)s %(message)s'), 'datefmt': '%Y-%m-%d %H:%M:%S' }, 'simple': { 'format': '%(levelname)s %(message)s' } }, 'handlers': { 'null': { 'level': 'DEBUG', 'class': 'logging.NullHandler', }, 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'verbose' } }, 'loggers': { 'testlogger': { 'handlers': ['console'], 'level': 'INFO', } } } DEBUG_PROPAGATE_EXCEPTIONS = True COMPRESS_ENABLED = os.environ.get('COMPRESS_ENABLED', False)
问题原因
findstatic命令用法错误:该命令不需要传入本地全路径,只需传入静态文件的相对路径(如css/home.css),全路径会触发Django的安全路径校验,导致报错。- 缺少
STATICFILES_DIRS配置:当前配置未指定项目根目录的static文件夹为静态文件来源,Django只会收集各app下static目录的文件,根目录的静态文件不会被纳入收集范围。 - WhiteNoise本地配置冲突:本地开发时启用
CompressedStaticFilesStorage和WHITENOISE_KEEP_ONLY_HASHED_FILES = True,会压缩文件并只保留带哈希的版本,干扰静态文件的正常收集和查找。
解决方案
1. 修正findstatic命令
使用相对路径查找静态文件:
python manage.py findstatic css/home.css
2. 添加STATICFILES_DIRS配置
在settings.py的静态文件配置区域,添加项目根目录的static文件夹:
# 放在STATIC_URL下方 STATICFILES_DIRS = [ BASE_DIR / "static", ]
此配置让Django同时扫描项目根目录和各app下的static文件夹。
3. 调整WhiteNoise本地开发配置
本地开发时临时禁用压缩和哈希文件功能,避免干扰:
# 替换原STORAGES和WHITENOISE配置 if not IS_HEROKU_APP: STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", }, } WHITENOISE_KEEP_ONLY_HASHED_FILES = False else: STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "whitenoise.storage.CompressedStaticFilesStorage", }, } WHITENOISE_KEEP_ONLY_HASHED_FILES = True
4. 重新执行collectstatic
配置完成后,运行收集命令:
python manage.py collectstatic
确认提示时输入yes,即可将所有静态文件复制到staticfiles目录。
内容的提问来源于stack exchange,提问作者Omar Gonzales
相关产品推荐
相关产品推荐

