关闭Debug后Django项目触发TypeError的问题求助
Django Debug=False时触发TypeError问题排查与解决
一直用Debug模式运行Django项目,切换为Debug=False后抛出错误:
TypeError: expected str, bytes or os.PathLike object, not NoneType
进一步排查发现,admin/js/jquery.js对应的absolute_path变量值为None。
整理的关键线索:
- 问题根源在
django-cloudinary-storage库中; - 大概率是执行
python manage.py collectstatic命令后出现的(此前从未执行过该命令); Debug=True时项目运行完全正常,仅关闭Debug模式时触发错误。
相关配置片段(settings.py)
STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) STATICFILES_STORAGE = 'cloudinary_storage.storage.StaticHashedCloudinaryStorage' STATICFILES_FINDERS = [ 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', ]
完整错误栈(Traceback)
Traceback (most recent call last): File "/opt/homebrew/Cellar/python@3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 973, in _bootstrap_inner self.run() File "/opt/homebrew/Cellar/python@3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 910, in run self._target(*self._args, **self._kwargs) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/utils/autoreload.py", line 64, in wrapper fn(*args, **kwargs) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/core/management/commands/runserver.py", line 157, in inner_run handler = self.get_handler(*args, **options) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/contrib/staticfiles/management/commands/runserver.py", line 31, in get_handler handler = super().get_handler(*args, **options) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/core/management/commands/runserver.py", line 78, in get_handler return get_internal_wsgi_application() File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/core/servers/basehttp.py", line 47, in get_internal_wsgi_application return import_string(app_path) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/utils/module_loading.py", line 30, in import_string return cached_import(module_path, class_name) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/utils/module_loading.py", line 15, in cached_import import_module(module_path) File "/opt/homebrew/Cellar/python@3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/importlib/__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1030, in _gcd_import File "<frozen importlib._bootstrap>", line 1007, in _find_and_load File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 680, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 850, in exec_module File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed File "/Users/ryanoh/Projects/crystalize/crystalize/wsgi.py", line 16, in <module> application = get_wsgi_application() File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/core/wsgi.py", line 13, in get_wsgi_application return WSGIHandler() File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/core/handlers/wsgi.py", line 126, in __init__ self.load_middleware() File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/core/handlers/base.py", line 61, in load_middleware mw_instance = middleware(adapted_handler) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/middleware.py", line 51, in __init__ self.add_files(self.static_root, prefix=self.static_prefix) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/base.py", line 113, in add_files self.update_files_dictionary(root, prefix) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/base.py", line 125, in update_files_dictionary self.add_file_to_dictionary(url, path, stat_cache=stat_cache) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/base.py", line 136, in add_file_to_dictionary static_file = self.get_static_file(path, url, stat_cache=stat_cache) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/base.py", line 210, in get_static_file self.add_cache_headers(headers, path, url) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/base.py", line 231, in add_cache_headers if self.immutable_file_test(path, url): File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/middleware.py", line 146, in immutable_file_test static_url = self.get_static_url(name_without_hash) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/whitenoise/middleware.py", line 169, in get_static_url return decode_if_byte_string(staticfiles_storage.url(name)) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/contrib/staticfiles/storage.py", line 166, in url return self._url(self.stored_name, name, force) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/contrib/staticfiles/storage.py", line 145, in _url hashed_name = hashed_name_func(*args) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/django/contrib/staticfiles/storage.py", line 394, in stored_name self.hashed_name(name, content=None, filename=intermediate_name) File "/Users/ryanoh/Projects/crysenv/lib/python3.9/site-packages/cloudinary_storage/storage.py", line 286, in hashed_name content = open(absolute_path, 'rb') TypeError: expected str, bytes or os.PathLike object, not NoneType
问题原因分析
当Debug=False时,Django不再自动提供静态文件服务,转而依赖已收集的静态文件或第三方存储服务。这里的矛盾点在于:
StaticHashedCloudinaryStorage会将静态文件上传到Cloudinary远程存储,本地并不会保留这些文件的副本(或者collectstatic后本地的文件结构和存储期望的不匹配);- Whitenoise中间件在初始化时会扫描本地静态文件目录,尝试为文件添加缓存头,当它处理到已上传到Cloudinary的文件(比如admin的jquery.js)时,会调用存储的
url方法生成哈希文件名,但django-cloudinary-storage在计算哈希时需要读取本地文件,此时本地找不到对应文件,导致absolute_path为None,触发打开文件的TypeError。
解决方法
方法1:替换为非哈希版本的Cloudinary存储
将STATICFILES_STORAGE改为不带哈希的版本,避免计算哈希时需要读取本地文件:
STATICFILES_STORAGE = 'cloudinary_storage.storage.StaticCloudinaryStorage'
这种方法简单直接,但失去了静态文件哈希缓存的优势,需要手动处理缓存刷新。
方法2:让Admin静态文件使用本地存储
通过自定义存储后端,让Django Admin的静态文件不使用Cloudinary,而是保留在本地:
import os from django.contrib.staticfiles.storage import StaticFilesStorage from cloudinary_storage.storage import StaticHashedCloudinaryStorage from django.conf import settings class AdminStaticStorage(StaticFilesStorage): def __init__(self, *args, **kwargs): kwargs['location'] = os.path.join(settings.STATIC_ROOT, 'admin') super().__init__(*args, **kwargs) # 配置静态文件存储映射 STATICFILES_STORAGES = { 'default': { 'BACKEND': 'cloudinary_storage.storage.StaticHashedCloudinaryStorage', }, 'admin': { 'BACKEND': 'your_project.settings.AdminStaticStorage', 'LOCATION': 'static/admin/', } }
同时需要确保collectstatic时将Admin的静态文件收集到本地目录。
方法3:禁用Whitenoise的Immutable文件检测
修改Whitenoise的配置,跳过对Cloudinary存储文件的缓存头检测:
WHITENOISE_IMMUTABLE_FILE_TEST = lambda path, url: False
这种方法会关闭所有文件的永久缓存检测,可能影响缓存效率,但能快速解决当前错误。
方法4:确保本地保留静态文件副本
执行collectstatic时添加--no-post-process参数,避免Cloudinary存储删除本地文件:
python manage.py collectstatic --no-post-process
这样本地STATIC_ROOT目录会保留所有静态文件的副本,django-cloudinary-storage就能找到absolute_path计算哈希了。不过这种方法会占用本地存储空间,且需要同步本地和Cloudinary的文件版本。
内容的提问来源于stack exchange,提问作者RyanOh
相关产品推荐
相关产品推荐

