ValueError: Missing staticfiles manifest entry for 'favicon.ico'

ValueError: Missing staticfiles manifest entry for 'favicon.ico'

我在 运行 python manage.py test 时收到 ValueError。我的项目名为 fellow_go,我目前正在开发一个名为 pickup.

的应用程序

请注意,此错误是在相对较新的 Django 提交中添加的:Fixed #24452 -- Fixed HashedFilesMixin correctness with nested paths.

======================================================================
ERROR: test_view_url_exists_at_desired_location (pickup.tests.test_view.HomePageViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/sunqingyao/PycharmProjects/fellow_go/pickup/tests/test_view.py", line 10, in test_view_url_exists_at_desired_location
    resp = self.client.get('/', follow=True)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/test/client.py", line 536, in get
    **extra)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/test/client.py", line 340, in get
    return self.generic('GET', path, secure=secure, **r)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/test/client.py", line 416, in generic
    return self.request(**r)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/test/client.py", line 501, in request
    six.reraise(*exc_info)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/utils/six.py", line 686, in reraise
    raise value
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/core/handlers/base.py", line 217, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/core/handlers/base.py", line 215, in _get_response
    response = response.render()
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/response.py", line 107, in render
    self.content = self.rendered_content
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/response.py", line 84, in rendered_content
    content = template.render(context, self._request)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/base.py", line 207, in render
    return self._render(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/test/utils.py", line 107, in instrumented_test_render
    return self.nodelist.render(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/loader_tags.py", line 177, in render
    return compiled_parent._render(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/test/utils.py", line 107, in instrumented_test_render
    return self.nodelist.render(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/templatetags/static.py", line 105, in render
    url = self.url(context)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/templatetags/static.py", line 102, in url
    return self.handle_simple(path)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/templatetags/static.py", line 117, in handle_simple
    return staticfiles_storage.url(path)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/contrib/staticfiles/storage.py", line 162, in url
    return self._url(self.stored_name, name, force)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/contrib/staticfiles/storage.py", line 141, in _url
    hashed_name = hashed_name_func(*args)
  File "/Users/sunqingyao/Envs/django_tutorial/lib/python3.6/site-packages/django/contrib/staticfiles/storage.py", line 432, in stored_name
    raise ValueError("Missing staticfiles manifest entry for '%s'" % clean_name)
ValueError: Missing staticfiles manifest entry for 'favicon.ico'

----------------------------------------------------------------------

fellow_go/settings.py

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

# ......

# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

fellow_go/urls.py

urlpatterns = i18n_patterns(
    url(r'^$', HomePageView.as_view(), name='index'),
    url(r'^pickup/', include('pickup.urls')),
    url(r'^accounts/', include('django.contrib.auth.urls')),
    url(r'^admin/', admin.site.urls),
    prefix_default_language=False
) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

fellow_go/pickup/views.py

class HomePageView(TemplateView):

    template_name = 'index.html'

fellow_go/templates/index.html

<link rel="icon" href="{% static "favicon.ico" %}">

fellow_go/pickup/tests/test_view.py

class HomePageViewTest(TestCase):

    def test_view_url_exists_at_desired_location(self):
        resp = self.client.get('/', follow=True)
        self.assertEqual(resp.status_code, 200)

我确实有一个 favicon.ico 文件:


奇怪的是,python manage.py runserver:

没有出现错误
/Users/sunqingyao/Envs/django_tutorial/bin/python3.6 /Users/sunqingyao/PycharmProjects/fellow_go/manage.py runserver 8000
Performing system checks...

System check identified no issues (0 silenced).
May 24, 2017 - 22:09:25
Django version 1.11.1, using settings 'fellow_go.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[24/May/2017 22:09:28] "GET / HTTP/1.1" 200 6276
[24/May/2017 22:09:28] "GET /static/css/style.min.css HTTP/1.1" 200 2474
[24/May/2017 22:09:28] "GET /static/css/ie10-viewport-bug-workaround.css HTTP/1.1" 200 430
[24/May/2017 22:09:28] "GET /static/js/ie10-viewport-bug-workaround.js HTTP/1.1" 200 685
[24/May/2017 22:09:28] "GET /static/js/opt-in.js HTTP/1.1" 200 511
[24/May/2017 22:09:28] "GET /static/css/datetimepicker.css HTTP/1.1" 200 12351
[24/May/2017 22:09:28] "GET /static/js/bootstrap-datetimepicker.js HTTP/1.1" 200 55741
[24/May/2017 22:09:35] "GET /static/favicon.ico HTTP/1.1" 200 766
Not Found: /apple-touch-icon-precomposed.png
[24/May/2017 22:09:35] "GET /apple-touch-icon-precomposed.png HTTP/1.1" 404 2678
Not Found: /apple-touch-icon.png
[24/May/2017 22:09:35] "GET /apple-touch-icon.png HTTP/1.1" 404 2642

请告诉我我的代码有什么问题。

尝试 运行:

python manage.py collectstatic

现在可以测试了吗?如果是这样,这可能是导致问题的配置:

STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

从 whitenoise v4 开始,这将失败,您应该使用:

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

相关:

查看 Django 文档: https://docs.djangoproject.com/en/1.11/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage.manifest_strict

whitenoise 包不一定会发生这种情况。将 STATIC_STORAGE 更改为 django.contrib.staticfiles.storage.ManifestStaticFilesStorage 将产生相同的错误,而 运行 测试以 Django 1.11.

开头

发生这种情况是因为 ManifestStaticFilesStorage 期望 staticfiles.json 存在并且 contain 请求文件。您可以通过 运行 ./manage.py collectstatic 确认并重试。

您通常不会在开发中看到此错误,因为当 DEBUG == TrueManifestStaticFilesStorage 切换到 non-hashed 网址时。

要克服这个问题,您必须确保:

STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'

这是默认值。

一种方法是覆盖测试设置 class:

from django.test import TestCase, override_settings
@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage')
class MyTest(TestCase):
    pass

或方法:

from django.test import TestCase, override_settings
class MyTest(TestCase):
    @override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage')
    def test_something(self):
        pass

如果您想继续使用WhiteNoise module in your Django 1.11 (or newer) project while preventing this "Missing staticfiles manifest entry" error, you need to disable the manifest_strict attribute by means of inheritance, as noted in Django documentation

如何实现?

首先,在您的项目目录中创建一个 storage.py 文件:

from whitenoise.storage import CompressedManifestStaticFilesStorage


class WhiteNoiseStaticFilesStorage(CompressedManifestStaticFilesStorage):
    manifest_strict = False

其次,编辑 settings.py 文件中的 STATICFILES_STORAGE 常量以指向这个新的 class,例如:

STATICFILES_STORAGE = 'my_project.storage.WhiteNoiseStaticFilesStorage'

如果您在测试期间引用静态文件,但自从创建该文件 (see these docs) 后您还没有 运行 ./manage.py collectstatic,Django 会引发此异常。

推荐的解决方法是:

During testing, ensure that the STATICFILES_STORAGE setting is set to something else like 'django.contrib.staticfiles.storage.StaticFilesStorage' (the default).

这是在您的 settings.py:

中执行此操作的简单方法
import sys

TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test'

STATICFILES_STORAGE = (
    'django.contrib.staticfiles.storage.StaticFilesStorage'
    if TESTING
    else 'whitenoise.storage.CompressedManifestStaticFilesStorage'
)

只是分享我对这个问题的解决方案,以防对其他人有所帮助。

我不小心在一些静态 URL 中包含了前导“/”,导致它们在清单中丢失。

解决方案是替换所有实例:

{% static '/path/to/some/file' %}

{% static 'path/to/some/file' %}

然后一切正常。

我遇到了同样的问题,我通过将 STATICFILES_STORAGE 更改为:

来解决
STATICFILES_STORAGE = 'cloudinary_storage.storage.StaticHashedCloudinaryStorage'

那么你应该运行:

python manage.py collectstatic

就我而言,我不确定为什么会发生这种情况,但是在我删除 heroku 设置后 django_heroku.settings(locals()) 一切又恢复了。

我的 setting.py

里有这个
DEBUG = False
try:
    from .local_setting import *
except ImportError:
    pass

在我删除 try 块后,一切都恢复正常了。

帮我解决了这个问题。

首先在settings.py

中添加这个
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': 'INFO',
        'class': 'logging.StreamHandler',
        'formatter': 'verbose'
    }
},
'loggers': {
    'django': {
        'handlers': ['console'],
        'level': 'DEBUG',
        'propagate': True,
    },
    'django.request': {
        'handlers': ['console'],
        'level': 'DEBUG',
        'propagate': False,
    },
}}

如果您使用的是 django-heroku,则在 settings.py 的末尾添加:

django_heroku.settings(config=locals(), staticfiles=False,logging=False)

在最新版本的 Whitenoise(目前为 5.2)中,您现在可以做..

WHITENOISE_MANIFEST_STRICT = False

在我的例子中,这是因为我使用 nginx (Docker) 来提供静态图像。这是在应用 运行 时发生的,而不是像 OP 那样在测试期间发生的。

问题是我声明 STATIC_ROOT 在 Django 应用之外:

STATIC_ROOT = "../staticfiles"

我这样做是为了避免将资产不必要地复制到 Django 容器中。如果您使用默认的 STATICFILES_STORAGE,这会很好地工作,但是当使用 ManifestStaticFilesStorage 时,静态文件查找失败,因为它无法在 Django 容器的目录中找到清单文件资产。

解决方案是简单地将静态文件声明为存在于 Django 图像上:

STATIC_ROOT = "staticfiles"

这确实创建了静态文件的副本:一份在 nginx 容器上,一份在 Django 上,但这意味着 Django 查找逻辑成功,即使文件是从 nginx 提供的。

另一种选择是禁用 manifest_strict 属性:

storage.ManifestStaticFilesStorage.manifest_strict

If a file isn’t found in the staticfiles.json manifest at runtime, a ValueError is raised. This behavior can be disabled by subclassing ManifestStaticFilesStorage and setting the manifest_strict attribute to False – nonexistent paths will remain unchanged.

环境:Python 3.8,Django 3.1.5

基本上我不使用whitenoise。在我看来,Django 的 ManifestStaticFilesStorage class 在收集静态文件方面做得很好。它添加了唯一的哈希值,运行速度快,不需要任何其他依赖项。

在生产服务器上(静态文件由 nginx 从 'public' 文件夹提供)我的静态文件设置如下所示:

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'public', 'static')
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"

仅此而已。在 运行 python manage.py collectstatic 之后使用此配置,Django 将从 static 文件夹中获取所有文件并将其移动到 public 中。它还将创建具有唯一 ID 的每个文件的副本,并将创建 staticfiles.json,其中包含所有带有原始静态文件名及其“散列”版本的静态文件映射,例如

{... "css/main.css": "css/main.31cdb680414e.css", main.js": "main.b08f762abac7.js"...}

使用这种方法,如果您在模板中使用:{% static 'images/my-image.jpg' %} 它将被转换为 path_to_image/my-image.828172380.jpg 这非常方便,尤其是当您更改 css 或 js 文件中的某些内容并希望将更改应用于所有内容而无需清除浏览器缓存时。

一条重要提示 如果您要在开头添加带有斜杠的静态文件,您可能会遇到此处描述的问题“Missing staticfiles manifest for...”。所以在你的模板中:

这行得通

<div class="slide slide1" style="background-image: url('{% static 'images/slider/129557309.jpg' %}');">

这是错误的,不会起作用,你会有例外

<div class="slide slide1" style="background-image: url('{% static '/images/slider/129557309.jpg' %}');">

差别很小,但你必须记住它。希望对您有所帮助:)

我遇到了同样的问题;每次我 运行 我的服务器使用 DEBUG = False 时,我都会得到“缺少静态文件清单条目”。

我花了好几个小时才弄清楚问题出在我的静态链接开头包含“/”。

例如: {% static '/app/styles/main.css' %} 而不是 {% static 'app/styles/main.css' %}