Background
django.contrib.staticfiles
django.contrib.staticfiles是django1.3新增的一个app来帮助开发者管理静态文件(js,css等)。
在我使用的 Django 1.6.11版本中,默认已安装并加载了 staticfiles
App,
INSTALLED_APPS = [
# 'django.contrib.admin',
# 'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core',
]
STATIC_URL
使用 STATIC_URL
管理静态文件( images, JavaScript, CSS)
在项目的 setting.py 中声明:
STATIC_URL = '/static/'
新建项目myproject:
$ django-admin.py startproject TestDjango
在项目中新建一个app名叫hello“:
$ cd TestDjango
$ python manage.py startapp hello
$ ls
hello TestDjango manage.py
在项目的settings.py文件中INSTALLED_APPS中配置hello app:
INSTALLED_APPS = (
...
'hello',
)
在hello app下建一个static目录用来存放静态文件:
$ cd hello
$ mkdir static
$ ls
__init__.py models.py static tests.py views.py
然后在static目录新建一个test.js的静态文件:
$ cd static/
$ ls
test.js
$ cat test.js
alert("load test.js successfully");
当前项目结构:
tree
.
├── TestDjango
├── hello
│ ├── static
│ │ └── test.js
│ ├── ...
└── ...
运行项目:
$ python manage.py runserver 0.0.0.0:8001
通过url访问:
这里很奇怪的是,这个 static
文件夹是位于你的 Django App 文件夹根目录中的(而不是你的 Django Project 文件夹根目录中),而你指定的明明是 STATIC_URL = '/static/'
。
这其实是因为使用 STATIC_URL
定义的方式,静态资源文件夹只能被一个 Django App 使用,
在 HTML 中嵌入静态资源
在 settings.py中指定 templates:
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',
],
},
},
]
在项目的根目录下创建一个 templates 文件夹文件夹:
$ mkdir templates
在 templates 文件夹中定义一个 a.html:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>a</title>
<link href="{% static 'test.js' %}" rel="stylesheet">
</head>
<body>
a's body
</body>
</html>
此时的文件结构:
$ tree
├── TestDjango
│ ├── ...
├── hello
│ ├── static
│ │ └── test.js
│ ├── ...
├── templates
├── a.html
└── ...
在 hello App 的 views.py 中定义一个 view:
def a(request):
return render(request, 'a.html', locals())
在项目下的 urls.py 中定义路由:
from django.conf.urls import url
# from django.contrib import admin
from hello import views
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^a/',views.a)
]
当访问 http://127.0.0.1:8001/a 时:
STATICFILES_DIRS
这其实是因为使用 STATIC_URL
定义的方式,静态资源文件夹只能被一个 Django App 使用。
如果当我们的 Django Project 中,有多个 Django App 时,使用 STATICFILES_DIRS
则可以更科学的管理静态资源。
Format example:
STATICFILES_DIRS = [
"/home/special.polls.com/polls/static",
"/home/polls.com/polls/static",
"/opt/webfiles/common",
]
Note that these paths should use Unix-style forward slashes, even on Windows (e.g. "C:/Users/user/mysite/extra_static_content"
).
使用 STATICFILES_DIRS
管理静态资源
在 settings.py 中定义:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
注意:
- 不能不声明
STATIC_URL
,而只声明STATICFILES_DIRS
,否则会有错误:django.core.exceptions.ImproperlyConfigured: You're using the staticfiles app without having set the required STATIC_URL setting.
。 - 不能进行
STATIC_URL = '/'
的声明,否则路由机制会出现问题。
在项目中新建一个app名叫hello2:
$ cd TestDjango
$ python manage.py startapp hello2
$ ls
TestDjango hello hello2 manage.py templates
在hello2 的 views.py 中增加:
def b(request):
# return HttpResponse("return this string")
context = {}
context['hello'] = 'Hello World!'
return render(request, 'b.html', context)
在 urls.py 中修改整个 Django Project 的路由规则为:
from django.conf.urls import url
from hello.views import a
from hello2.views import b
urlpatterns = [
url(r'^a/$', a),
url(r'^b/$', b),
]
目录结构为:
$ tree /Users/wei.shi/Downloads/TestDjango
/Users/wei.shi/Downloads/TestDjango
├── TestDjango
│ ├── ...
├── hello
│ ├── views.py
│ └── ...
├── hello2
│ ├── views.py
│ └── ...
├── static
│ └── test.js
├── templates
├── a.html
└── b.html
└── ...
最终,无论是访问 http://127.0.0.1:8001/a/ 还是 http://127.0.0.1:8001/b/,一切都正常:
存疑
然而发现一个神奇的地方,当在 settings.py 中设置为:
STATIC_URL = '/aabbccdd/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
在 HTML 页面中,仍然采用和上面一样的方法来加载静态资源,即:
{% load static %}
...
<link href="{% static 'test.js' %}" rel="stylesheet">
虽然请求 http://127.0.0.1:8001/a/ 时,仍能正常获取到静态资源,但是在Chrome DevTools 中,看到的请求 URL 竟然是 http://127.0.0.1:8001/aabbccdd/test.js:
Prefixes (optional)
In case you want to refer to files in one of the locations with an additional namespace, you can optionally provide a prefix as (prefix, path)
tuples, e.g.:
STATICFILES_DIRS = [
# ...
("downloads", "/opt/webfiles/stats"),
]
For example, assuming you have STATIC_URL
set to '/static/'
, the collectstatic
management command would collect the “stats” files in a 'downloads'
subdirectory of STATIC_ROOT
.
This would allow you to refer to the local file /opt/webfiles/stats/polls_20101022.tar.gz
with /static/downloads/polls_20101022.tar.gz
in your templates, e.g.:
<a href="{% static "downloads/polls_20101022.tar.gz" %}">
部署静态文件(Deploy Static Files)
django.contrib.staticfiles
provides a convenience management command for gathering static files in a single directory so you can serve them easily.
Most larger Django sites use a separate Web server – i.e., one that’s not also running Django – for serving static files. This server often runs a different type of web server – faster but less full-featured. Some common choices are:
- Nginx
- A stripped-down version of Apache
在 Django Project 的 settings.py 中设置:
STATIC_ROOT = "/var/www/example.com/static/"
执行:
$ python manage.py collectstatic
此后,所有的静态资源都会被拷贝到 /var/www/example.com/static/
下。
我们可以根据具体项目中的情况,将这些静态资源拷贝到 CDN 或者交由 Nginx 这样的 Web server 帮来我们处理静态资源的请求。
如果需要部署到 CDN,则可以在 Django Project 的 settings.py 中设置:
STATIC_URL = 'https://your.cdn./'
这样,所有的静态文件的 URL 前缀都会自动变成你这个的这个 CDN 的地址:
Reference
- https://docs.djangoproject.com/en/1.11/howto/static-files/
- https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-STATICFILES_STORAGE
- https://docs.djangoproject.com/en/1.11/howto/static-files/deployment/
- https://www.cnblogs.com/starof/p/4682812.html