一、背景
Django框架下,HTML页面访问CSS、JS、IMG等静态文件,报404 Not Found。
二、最终解决方法
- settings.py文件配置好STATiC_URL、STATICFILES_DIRS以后,同时配置DEBUG=True
- HTML页面使用使用load标签导入static标签:{%load static%},而不是导入staticfiles标签。
三、相关知识
(1)Djangon生产环境静态资源的处理
Django 关闭DEBUG模式后,就相当于是生产环境了。
Django框架一旦作为生产环境,它的静态文件访问接口就不能从Django框架中走,必须在Django框架前端部署nginx或者其他web服务器来提供静态访问入口
With debug turned off Django won't handle static files for you any more - your production web server (Apache or something) should take care of that.
nginx配置如下:
server {
listen 80;
server_name 127.0.0.1
charset UTF-8;
access_log /var/log/nginx/django_pro01_access.log;
error_log /var/log/nginx/django_pro01_error.log;
client_max_body_size 75M;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8000;
uwsgi_read_timeout 2;
}
# 在nginx中要单独做访问/static/目录的路由
location /static {
expires 30d;
autoindex on;
add_header Cache-Control private;
alias /usr/share/nginx/django_pro01/static/;
}
}
所有静态文件都应该从“/usr/share/nginx/django_pro01/static/”这个目录中(也就是上面定义的STATIC_ROOT)获取。
运行 python manage.py collectstatic 命令的目的,是将在开发模式中定义的静态目录,统一拿到STATIC_ROOT目录下,对外提供“/static”(STATIC_URL)为访问URL:
1.首先从Django的扩展包中,将admin管理后台的jss 和css等静态文件拷贝到配置文件中的STATIC_ROOT目录下。
2.然后将STATICFILES_DIRS 列表中所有目录下的内容也拷贝到STATIC_ROOT目录下
(2)最佳实践
最佳的配置方式是将所有的App 下面的静态文件统一放置到一个目录下面,然后将该目录设置为STATICFILES_DIRS,STATIC_ROOT则设置为另外的目录:
# 对外提供WEB访问时的URL地址
STATIC_URL = '/static/'
# 开发阶段放置项目自己的静态文件,不能包含STATIC_ROOT路径
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'staticfiles'),
)
# 执行collectstatic命令后会将项目中的静态文件(包括STATICFILES_DIRS、自带admin的静态文件)收集到该目录下面来(所以不应该在该目录下面放置自己的一些静态文件,因为会覆盖掉)
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
在开发阶段Django把/static 映射到django.contrib.staticfiles这个App,django.contrib.staticfiles自动地从STATICFILES_DIRS、STATIC_ROOT以及各个App的static子目录里面搜索静态文件。
一旦部署到开发环境上,settings.py不需要重新编写,只要在Nginx的配置文件里面写好映射,/static将会被Nginx处理。
django.contrib.staticfiles虽然仍然存在,但因为不会接收到以/static/开始的路径,所以将不会产生作用。不必担心Django会使处理速度变慢。
当settings.DEBUG is False的时候,staticfiles将自动关闭。
(3)Django继续使用静态资源的办法
Django在非debug模式下,不处理静态资源文件,原因可能是性能,使用CDN比较好,但是小应用就不用了,解决办法参考:
- python manage.py runserver 0:8088 --insecure
- https://github.com/evansd/whitenoise
- https://github.com/heroku-python/dj-static
(4)在django中使用静态文件
- 首先确保django.contrib.staticfiles在INSTALLED_APPS中已配置。
- 在settings中定义 STATIC_URL 。 STATIC_URL = '/static/'
- 在static目录中存放静态文件,比如:/static/my_app/example.jpg。推荐static目录和项目目录、模板文件夹目录同级
- 如果有别的静态资源文件,不在static目录下,可以通过 STATICFILES_DIRS来指定额外的静态文件搜索目录。
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
...
]
5. 在模板中使用load标签去加载静态文件,通过模板标签static和给定的相对路径来构成一个URL
{% load static %}
<img src="{% static "my_app/example.jpg" %}" alt="My image"/>
当然也可以直接使用路径
<img src="/static/my_app/example.jpg" alt="My image"/>
(5)汇集静态资源到指定目录
python manage.py collectstatic在执行时,django默认会去查看定义在STATICFILES_DIRS里的目录,以及在INSTALLED_APPS里定义了的app的static目录。如果这些目录下有文件,则把文件全部收集起来,拷贝到STATIC_ROOT目录下。当使用django的runserver时,如果请求的是一个静态文件,django也是会默认查看上述的ROOT、DIRS和static目录。但是,在部署到服务器上时,此规则就不使用了
(6)安装static标签
如果不想每次在模版中加载静态文件都使用load加载static标签,那么可以在settings.py中的TEMPLATES/OPTIONS添加'builtins':['django.templatetags.static'],这样以后在模版中就可以直接使用static标签,而不用手动的load了。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, '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',
],
#添加在这个位置
'builtins' : [
'django.templatetags.static'
],
},
},
]
注意: 位置不要添加错误了
(7)手动映射静态文件的url与静态文件的路径
如果没有在settings.INSTALLED_APPS中添加django.contrib.staticfiles。那么我们就需要手动的将请求静态文件的url与静态文件的路径进行映射了。下面的不常用,但是可以了解一下。
示例代码如下:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
re_path(r'^static/(?P<path>.*)$', static.serve, {'document_root': settings.STATIC_ROOT}, name='static'),
]
settings.py 文件设置
STATIC_URL = '/static/'
STATIC_ROOT = 'static'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "/static/"),
]
但平时我们并不会用到这个,Django内置已经将django.contrib.staticfiles添加进去了的,我们为什么要给他删除来自找麻烦呢?放在这里也只是提供一个参考,了解一下。
(8)static staticfiles 标签区别
Django 1.9及更早版本{%load staticfiles%}从contrib应用程序加载静态模板标签,包括static等标签。,该应用程序具有比内置django.core.static更多的功能;{%load static%}从内置django.core.static加载静态模板标签static。
最重要的区别是staticfiles可以管理存储在CDN上的文件,因为它的解析器可以管理哈希值. core.static只将STATIC_URL附加到静态文件名,如果您正在处理文件,这是不够的(例如,添加md5哈希以清除版本之间的缓存)。
这种差异是由于管理非本地存储文件的功能并没有包含在Django的核心软件包中,但对许多开发人员来说仍然有用。
从Django 1.10 and onwards(也是see ticket in Django tracker)开始,{%load static%}将在内部使用staticfiles(如果激活)(否则保持默认行为),并且不推荐使用contrib包中的template tag以避免混淆.
- 在Django 1.10之前:staticfiles加载一个模板标签,可以管理django.core.static不能管理(或不容易)的非本地存储;
- 来自Django 1.10:contrib.staticfiles应用程序仍然存在但其模板标签除{%static%}模板标签保留外,其余标签将被删除;
- 从Django 2.0:{%load staticfiles%}被删除。
现在,如果您使用的Django 版本是1.10以前的,并且需要使用相关的contrib应用程序(并且您知道为什么使用它),则使用staticfiles template tags,否则只使用static.