staticfiles 应用

django.contrib.staticfiles 从你的每一个应用程序(以及你指定的任何其他地方)收集静态文件到一个单一的位置,可以很容易地在生产中服务。

参见

关于静态文件应用的介绍和一些使用示例,请参见 管理静态文件(比如图片、JavaScript、CSS)。关于部署静态文件的指南,请参见 部署静态文件

管理命令

django.contrib.staticfiles 公开了三个管理命令。

collectstatic

django-admin collectstatic

将静态文件收集到 STATIC_ROOT 中。

重复的文件名默认的解析方式与模板解析的方式类似:首先在指定位置找到的文件将被使用。如果你感到困惑, findstatic 命令可以帮助你显示哪些文件被找到。

在随后运行 collectstatic 时(如果 STATIC_ROOT 不是空的),只有当文件的修改时间戳大于 STATIC_ROOT 中文件的时间戳时,才会被复制。因此,如果你从 INSTALLED_APPS 中删除一个应用程序,最好使用 collectstatic --clear 选项来删除过时的静态文件。

通过使用 启用的查找器 搜索文件。默认情况是在 STATICFILES_DIRS 中定义的所有位置和 INSTALLED_APPS 配置指定的应用程序的 'static' 目录中查找。

collectstatic 管理命令在每次运行后都会调用 STATICFILES_STORAGE 中的 post_process() 方法,并传递一个管理命令找到的路径列表。它还接收 collectstatic 的所有命令行选项。这是由 ManifestStaticFilesStorage 默认使用的。

默认情况下,收集的文件从 FILE_UPLOAD_PERMISSIONS 中获得权限,收集的目录从 FILE_UPLOAD_DIRECTORY_PERMISSIONS 中获得权限。如果你希望这些文件和/或目录有不同的权限,你可以将 静态文件存储类 中的任何一个子类化,并分别指定 file_permissions_mode 和/或 directory_permissions_mode 参数。例如:

from django.contrib.staticfiles import storage

class MyStaticFilesStorage(storage.StaticFilesStorage):
    def __init__(self, *args, **kwargs):
        kwargs['file_permissions_mode'] = 0o640
        kwargs['directory_permissions_mode'] = 0o760
        super().__init__(*args, **kwargs)

然后将 STATICFILES_STORAGE 设置为 'path.to.MyStaticFilesStorage'

一些常用的选项是:

--noinput, --no-input

不要提示用户进行任何形式的输入。

--ignore PATTERN, -i PATTERN

忽略与此 glob 样式模式匹配的文件、目录或路径。多次使用可以忽略更多的文件、目录或路径。当指定路径时,始终使用正斜线,即使在 Windows 上也是如此。

--dry-run, -n

除了修改文件系统外,其他都要做。

--clear, -c

在尝试复制或链接原始文件之前,先清除现有文件。

为每个文件创建一个符号链接,而不是复制。

--no-post-process

不要调用配置的 STATICFILES_STORAGE 存储后端的 post_process() 方法。

--no-default-ignore

不要忽视常见的私有 glob 样式模式 'CVS''.*''*~'

完整的选项列表,请参考命令本身的帮助,运行:

$ python manage.py collectstatic --help
...\> py manage.py collectstatic --help

自定义忽略的模式列表

默认的忽略模式列表 ['CVS', '.*', '*~'],可以用比在每次 collectstatic 调用时提供 --ignore 命令选项更持久的方式进行自定义。提供一个自定义的 AppConfig 类,覆盖这个类的 ignore_patterns 属性,并在你的 INSTALLED_APPS 设置中用该类路径替换 'django.contrib.staticfiles'

from django.contrib.staticfiles.apps import StaticFilesConfig

class MyStaticFilesConfig(StaticFilesConfig):
    ignore_patterns = [...]  # your custom ignore list

findstatic

django-admin findstatic staticfile [staticfile ...]

通过启用的查找器搜索一个或多个相对路径。

例如:

$ python manage.py findstatic css/base.css admin/js/core.js
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css
  /home/polls.com/core/static/css/base.css
Found 'admin/js/core.js' here:
  /home/polls.com/src/django/contrib/admin/media/js/core.js
...\> py manage.py findstatic css\base.css admin\js\core.js
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css
  /home/polls.com/core/static/css/base.css
Found 'admin/js/core.js' here:
  /home/polls.com/src/django/contrib/admin/media/js/core.js
findstatic --first

默认情况下,会找到所有匹配的位置。要只返回每个相对路径的第一个匹配点,请使用 --first 选项:

$ python manage.py findstatic css/base.css --first
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css
...\> py manage.py findstatic css\base.css --first
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css

这是一个调试辅助工具,它会告诉你到底哪个静态文件会被收集到一个给定的路径。

通过将 --verbosity 标志设置为 0,你可以抑制额外的输出,只获取路径名:

$ python manage.py findstatic css/base.css --verbosity 0
/home/special.polls.com/core/static/css/base.css
/home/polls.com/core/static/css/base.css
...\> py manage.py findstatic css\base.css --verbosity 0
/home/special.polls.com/core/static/css/base.css
/home/polls.com/core/static/css/base.css

另一方面,通过将 --verbosity 标志设置为 2,可以得到所有被搜索的目录。

$ python manage.py findstatic css/base.css --verbosity 2
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css
  /home/polls.com/core/static/css/base.css
Looking in the following locations:
  /home/special.polls.com/core/static
  /home/polls.com/core/static
  /some/other/path/static
...\> py manage.py findstatic css\base.css --verbosity 2
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css
  /home/polls.com/core/static/css/base.css
Looking in the following locations:
  /home/special.polls.com/core/static
  /home/polls.com/core/static
  /some/other/path/static

runserver

django-admin runserver [addrport]

如果 staticfiles 应用程序被 installed,则覆盖核心 runserver 命令,并增加静态文件的自动服务。文件服务不通过 MIDDLEWARE 运行。

该命令增加了这些选项:

--nostatic

使用 --nostatic 选项来完全禁止使用 静态文件 应用程序提供静态文件。只有当 静态文件 应用在你的项目的 INSTALLED_APPS 配置中时,这个选项才可用。

使用实例:

$ django-admin runserver --nostatic
...\> django-admin runserver --nostatic
--insecure

使用 --insecure 选项来强制使用 静态文件 应用服务静态文件,即使 DEBUG 设置为 False。通过使用这个选项,你承认了这样的事实,即这是 效率低下的,而且可能是 不安全的。这仅用于本地开发,不应在生产中使用,并且只有当 静态文件 应用在你的项目的 INSTALLED_APPS 设置中时才可用。

--insecure 不能与 ManifestStaticFilesStorage 一起工作。

使用实例:

$ django-admin runserver --insecure
...\> django-admin runserver --insecure

存储

StaticFilesStorage

class storage.StaticFilesStorage

FileSystemStorage 存储后端的一个子类,分别使用 STATIC_ROOT 配置作为基础文件系统位置和 STATIC_URL 配置作为基础 URL。

storage.StaticFilesStorage.post_process(paths, **options)

如果这个方法定义在一个存储上,那么在每次运行后都会被 collectstatic 管理命令调用,并得到本地存储空间和找到的文件路径作为一个字典,以及命令行选项。它产生的元组有三个值。original_path, processed_path, processed。路径值是字符串,processed 是一个布尔值,表示该值是否经过后处理,如果后处理失败则表示异常。

ManifestStaticFilesStorage 在幕后使用它将路径替换为它们的哈希对应物,并适当地更新缓存。

ManifestStaticFilesStorage

class storage.ManifestStaticFilesStorage

StaticFilesStorage 存储后台的一个子类,它通过在文件名上附加文件内容的 MD5 哈希值来存储它处理的文件名。例如,文件 css/styles.css 也会被保存为 css/styles.55e7cbb9ba48.css

这个存储的目的是为了继续服务于旧文件,以防某些页面仍然引用这些文件,例如,因为它们被你或第三方代理服务器缓存了。此外,如果你想在部署的文件上应用 远期失效头信息 ,以加快后续页面访问的加载时间,它是非常有用的。

存储后台会自动将保存文件中找到的与其他保存文件相匹配的路径替换为缓存副本的路径(使用 post_process() 方法)。用于查找这些路径的正则表达式(django.contrib.staticfiles.storage.HashedFilesMixin.patterns)默认涵盖了 @import 规则和 url() 语句的 层叠样式表 。例如,''css/styles.css' 文件的内容为

@import url("../admin/css/base.css");

会通过调用 ManifestStaticFilesStorage 存储后台的 url() 方法来替换,最终保存一个 'css/styles.55e7cbb9ba48.css' 文件,内容如下:

@import url("../admin/css/base.27e20196a850.css");
storage.ManifestStaticFilesStorage.max_post_process_passes

由于静态文件可能会引用其他需要替换路径的静态文件,因此可能需要多次替换路径,直到文件哈希值收敛。为了防止由于哈希值不收敛而导致无限循环(例如,如果 'foo.css' 引用 'bar.css',而后者引用 'foo.css'),在放弃后处理之前有一个最大的传递次数。在引用数量较多的情况下,可能需要更多的传递次数。通过子类 ManifestStaticFilesStorage 并设置 max_post_process_passes 属性来增加最大传递次数。默认值为 5。

要启用 ManifestStaticFilesStorage,你必须确保满足以下要求:

  • STATICFILES_STORAGE 设置为 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
  • DEBUG 设置为 False
  • 通过使用 collectstatic 管理命令,你已经收集了所有静态文件

由于在运行时创建 MD5 哈希可能会给网站带来性能负担,staticfiles 会自动将所有处理过的文件的哈希名映射存储在一个名为 staticfiles.json 的文件中。当你运行 collectstatic 管理命令时就会发生一次。

storage.ManifestStaticFilesStorage.manifest_strict

如果在运行时在 staticfiles.json 清单中没有找到文件,就会引发 ValueError。这种行为可以通过子类 ManifestStaticFilesStorage 并将 manifest_strict 属性设置为 False 来禁止,不存在的路径将保持不变。

由于需要运行 collectstatic,在运行测试时通常不应该使用这个存储,因为 collectstatic 并不是作为正常测试配置的一部分来运行的。在测试过程中,确保将 STATICFILES_STORAGE 设置为类似 'django.contrib.staticfiles.storage.StaticFilesStorage' (默认)这样的其他配置。

storage.ManifestStaticFilesStorage.file_hash(name, content=None)

创建文件的哈希名时使用的方法。需要返回给定文件名和内容的哈希值。默认情况下,它从上面提到的内容块中计算出一个 MD5 哈希。可以随意覆盖这个方法,使用自己的哈希算法。

ManifestFilesMixin

class storage.ManifestFilesMixin

使用这个混入和一个自定义的存储来附加文件内容的 MD5 哈希到文件名中,就像 ManifestStaticFilesStorage 那样。

查找器模块

staticfiles 查找器有一个 searched_locations 属性,是查找器搜索的目录路径列表。使用示例:

from django.contrib.staticfiles import finders

result = finders.find('css/base.css')
searched_locations = finders.searched_locations

其他辅助功能

staticfiles 应用程序之外,还有一些其他的辅助功能来处理静态文件。

静态文件开发视图

静态文件工具主要是为了帮助将静态文件成功部署到生产中。这通常意味着一个单独的、专用的静态文件服务器,这在本地开发时是一个很大的开销。因此,staticfiles 应用程序中附带了一个 快速和肮脏的辅助视图,你可以在开发中使用它在本地服务文件。

views.serve(request, path)

该视图功能服务于开发中的静态文件。

警告

只有当 DEBUGTrue 时,该视图才会生效。

这是因为这个视图的 效率很低,而且可能 不安全。这只用于本地开发,不应该用于生产

注解

为了猜测服务文件的内容类型,这个视图依赖于 Python 标准库中的 mimetypes 模块,它本身依赖于底层平台的映射文件。如果你发现这个视图没有为某些文件返回正确的内容类型,很可能是平台的映射文件不正确或者需要更新。例如,可以通过安装或更新 Red Hat 发行版上的 mailcap 包、Debian 发行版上的 mime-support,或编辑 Windows 注册表中 HKEY_CLASSES_ROOT 下的键来实现。

该视图由 runserver 自动启用(将 DEBUG 设置为 True)。要在不同的本地开发服务器上使用该视图,请在主 URL 配置的结尾添加以下代码段:

from django.conf import settings
from django.contrib.staticfiles import views
from django.urls import re_path

if settings.DEBUG:
    urlpatterns += [
        re_path(r'^static/(?P<path>.*)$', views.serve),
    ]

注意,模式的开头(r'^static/')应该是你的 STATIC_URL 配置。

因为这个有点细,所以还有一个辅助功能可以帮你完成这个任务:

urls.staticfiles_urlpatterns()

这将返回适当的 URL 模式,用于向你已经定义的模式列表提供静态文件。像这样使用它:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns

# ... the rest of your URLconf here ...

urlpatterns += staticfiles_urlpatterns()

这将检查你的 STATIC_URL 配置,并相应地给视图设置静态文件。不要忘记设置 STATICFILES_DIRS 配置,让 django.contrib.staticfiles 知道除了应用程序目录中的文件外,还可以在哪里查找文件。

警告

只有当 DEBUGTrue,并且你的 STATIC_URL 的配置既不是空的,也不是完整的 URL,比如 http://static.example.com/,这个辅助函数才会起作用。

这是因为这个视图的 效率很低,而且可能 不安全。这只用于本地开发,不应该用于生产

支持“实时测试”的专门测试案例

class testing.StaticLiveServerTestCase

这个 untest TestCase 子类扩展了 django.test.LiveServerTestCase

就像它的父类一样,你可以用它来编写测试,涉及到运行被测代码,并通过 HTTP 与测试工具(如 Selenium、PhantomJS 等)进行消费,因为这需要静态资产也被发布。

但是由于它使用了上面描述的 django.contrib.staticfiles.views.service() 视图,它可以在测试执行时透明地叠加 staticfiles 查找器提供的资产。这意味着你不需要在测试配置之前或作为测试配置的一部分运行 collectstatic