0%

Django静态资源配置

静态文件

静态文件的配置,一般需要使用到以下几个参数

1
2
3
STATIC_URL
STATIC_ROOT
STATICFILES_DIRS

STATIC_URL

STATIC_URL 是必须设置的,提供了静态文件访问的映射关系,如设置 STATIC_URL='/static/' 时(名字可以自定义,这个是访问所有的静态文件的根名),访问静态文件的路径就是 127.0.0.1:8000/static/静态文件名。在设置了该参数之后,Django实际上就有了访问静态文件的能力,所以说该参数是必须设置的。

在开发模式下(DEBUG设置为True),Django提供了静态文件代理的功能,会自动识别每个 app下静态文件(前提是,这些静态文件夹必须设置在每个app之下,且使用的名字必须是static,这是因为Django内部做了相应的处理,只有名字 static 才会被Django自带的静态文件代理服务器识别),提供访问。

设置app下的静态文件夹的时候,内部最好有一个用当前app名字命名的文件夹,并在该文件夹下放置相应的静态文件(这是因为不做区分,万一多个app之间有同名的静态文件,Django就会混淆),此时这些静态文件的访问地址就是: 127.0.0.1:8000/static/app命名的文件夹/相应的静态文件
例如,第三方插件xadmin这个app就是这样设计的:
第三方插件xadmin图片

此外,设置了该参数之后,在模板层通过引入 { % load staticfiles % } [1]标签,可以在模板中使用 href="{ % static 'css/reset.css' % }"[1:1] 构建静态资源路径的构建,这样当对 STATIC_URL 指定的静态文件的根名方法改变的时候,不需要修改模板中的访问路径,依然能够访问,效果和{ % url '' % }[1:2]类似。

STATICFILES_DIRS

只在开发模式下有效,对于一些公共的静态文件,或者在项目中自建app的时候不想为每个app单独设置静态文件夹,为了方便管理,可以单独在项目的根目录下设置一个文件夹统一管理所有的静态文件(但是这个文件夹无法被开发模式下Django自带的静态文件代理服务定位到,所以必须使用STATICFILES_DIRS进行设置),设置如下:

1
2
3
4
5
6
7
8
9
# 全局静态文件访问配置
STATICFILES_DIRS = [
os.path.join(BASE_DIR, '集中管理的文件名')
]
# 也可以设置多个静态文件夹
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
os.path.join(BASE_DIR, 'xxx/static') # 可以设置多个静态文件查找路径
]

这样在项目根目录下创建 集中管理的文件名文件,在里面放置静态文件,此时静态文件的访问地址是 127.0.0.1:8000/static/集中管理的文件名中的静态文件

STATICFILES_DIRS 的设置只是提供给开发模式下的Django自带静态文件代理服务定位静态文件用的。

STATIC_ROOT

在Django项目部署上线的时候,DEBUG需要设置为False,Django 不再提供静态文件代理功能,app自带的静态文件夹分布在各app下无法访问到,此时需使用 pyhton manage.py collectstatic 收集所有的静态文件,STATIC_ROOT就是用来设置所有的静态文件的聚合目录,如:

1
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

使用 python manage.py collectstatic 之后,django会把所有的static文件都复制到STATIC_ROOT文件夹下。

小结

  1. 无论是开发模式还是生产环境下,Django项目都依赖STATIC_URL=’/static/'的设置,因为这提供了静态文件访问的映射关系,有了他,Django才能够访问静态文件。
  2. STATICFILES_DIRS用于指定在项目根目录下统一管理的静态文件夹的名字,但只是在开发过程中有效以及使用,生产环境下,所有的静态文件都将被收集到统一的目录下(包括 STATICFILES_DIRS 的),交给第三方静态服务器调度提供。
  3. 若存在app下的static和STATICFILES_DIRS设置中同名的文件,默认访问的是STATICFILES_DIRS设置的静态文件下的,所以在app下的static中再设置一个app名的文件夹对静态文件管理,这样在访问时加上app名127.0.0.1:8000/static/app名,这样可以有效避免一些重名问题。
  4. 关于static目录的位置设置使用建议,若website中的每个app的独立性非常强的话,就在每个单独的app下设置static目录,这样app就会支持热插拔,独立性强。若app的独立性不强,app之间相互联系的话,建议使用集中管理static的方法。但是无论使用哪种方式,在项目部署的时候,都会进行静态文件的收集,由第三方静态服务器管理。

media文件

设置和static类似,因为在开发模式下(DEBUG需要设置为True),Django并不提供media文件的代理服务,所以即使在开发模式下,也需要手动设置medai文件的代理。

配置

需要同时设置MEDIA_URL和MEDIA_ROOT

1
2
3
# media文件的路径
MEDIA_URL = "/media/" # 可以改名
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # media为放置 media文件的文件夹名

解释:
设置MEDIA_ROOT后,Django做了一定的处理,能够使上传的文件传到MEDIA_ROOT指定的文件中,如models.py中指定的模型有些有 upload_to="org/%Y/%m",这样指定后,就会在media中创建 org/年/月 的文件夹存储文件。此时仅仅设置 MEDIA_ROOT 参数,就可以完成上传时自动放到设置的media目录下。但是此时的图片访问地址是当前所在页面的地址,加上存储的地址,为当前所在地址/org/%Y/%m/图片

若想访问到meida中的地址,还需要设置MEDIA_URL="/media/" ,设置之后访问media的路径就变成了127.0.0.1:8000/media/org/%Y/%m/图片。但是目前通过这个地址还是访问不了media(这点和static不同),Django没有对media的访问做处理,还需要我们手动对url的访问处理:

1
2
3
4
# 在项目urls.py中设置url
from django.views.static import serve # 静态文件处理的view,该方法接受path参数
# 配置上传文件的访问url
url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),
1
2
3
4
5
6
7
8
9
from django.views.static import serve

def serve(request, path, document_root=None, show_indexes=False):
pass
'''
这个方法serve是一个专门用于处理静态文件的view,这里的用法就和我们定义一个view视图处理url请求一样,<path>中设置的参数path会传递给view处理函数,也就是这里的serve函数,
{"document_root": MEDIA_ROOT}这叫额外参数,为dict类型,额外参数只能被视图函数(这里的serve)读取
通过serve参数可见,设置的path和document_root都是serve()的参数
'''

此时就完成了media文件的访问。

问题

媒体文件都是通过models.py中模型通过设置 upload_to 字段将文件的路径存储在数据库中,文件存储在MEDIA_ROOT设置的路径之中,所以在使用的时候,数据库中只能读取到 upload_to 时的路径 /org/年/月/文件名,而这个路径是不完整的,想要访问到文件还需要添加MEDIA_URL设置的前缀。
在模板层中想要获得MEDIA_URL设置的前缀可以view视图进行传递,然后在模板层中使用 data-url="{ { MEDIA_URL } } { { org.image } }"[1:3],但是这样写的话,意味着要在每个views中传递MEDIA_URL参数,这是非常不好的。可以使用类似注入的方式,将MEDIA_URL注入到模板中,使其可以在模板中直接被调用。
Django自带了一些注入,如在模板中,直接可以使用{ % if request.user.is_authenticated % }[1:4]调用request.user设置直接使用user进行操作,这是因为在settings.py中的进行了如下的设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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', # 注册了该条语句,能够使用request
'django.contrib.auth.context_processors.auth', # 能够直接使用user, 返回的也是request.user
'django.contrib.messages.context_processors.messages',
],
},
},
]


def auth(request):
"""
Return context variables required by apps that use Django's authentication
system.

If there is no 'user' attribute in the request, use AnonymousUser (from
django.contrib.auth).
"""
if hasattr(request, 'user'):
user = request.user
else:
from django.contrib.auth.models import AnonymousUser
user = AnonymousUser()

return {
'user': user,
'perms': PermWrapper(user),
}

django中已经提供好了django.template.context_processors.media只要添进去即可
我们看一下这个函数media的逻辑:

1
2
def media(request):
return {'MEDIA_URL': settings.MEDIA_URL}

逻辑相当简单,这样我们也可以模仿使用类似的方式定义我们自己的context_processors
之后再模板中使用图片的方式为:src="{ { MEDIA_URL } }{ { hot_course.image } }"[1:5]

若不不使用模板层的context_processors注入方法,还可以使用image model(models.ImageField)的自带属性方法url,他会自动拼接形成一个可以方法的url,如src="{ { hot_course.image.url } }"[1:6]。实际使用中也推荐使用该种方法,因为不需要做额外的操作,直接调用图片属性的url,即可自动拼接成图片相应的访问地址。


  1. Django模版语法中,此处的两个中括号之间以及中括号和百分号之间是没有空格的,由于hexo的限制,写在一起无法显示,故作此说明。 ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎