「Django框架」-模板
bigegpt 2025-03-01 13:01 11 浏览
来源于公众号:Python野路子
一、模板介绍
我们之前学习的,都是在视图函数直接返回文本,在实际中我们更多的是带有样式的HTML代码,这样可以让浏览器渲染出非常漂亮的页面,目前市面上有非常多的模板系统,其中最常用的是DTL和Jinja2,DTL(Django Template Language),也就是Django自带的模板语言,当然也可以配置Django支持Jinja2,但是作为Django内置的模板语言,不会产生一些不兼容的情况,最好还是使用内置的。
1. DTL与普通的HTML文件区别
DTL模板是一种带有特殊语法的HTML文件,这个HTML文件可以被Django编译,可以传递参数进去,实现数据动态化,在编译完成后,生成一个普通的HTML文件,然后发送给客户端。
2. 模板渲染
可以使用render函数进行渲染,将数据渲染到指定的HTML模板中。
我们在之前的基础上,再新建一个article的app,除了刚开始第一个应用,我们在pycharm创建项目的时候,填了app名字,pycharm会自动帮我们创建应用,后续如果还要再新建应用,我们都要使用命令方式才能新建app。
应用创建完成了,接下来我们需要在配置文件settings.py里面注册应用app。
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'user.apps.UserConfig',#使用pycharm创建的应用,pycharm会自动注册
'article'#手工命令方式创建的应用app,需要手工在这注册应用!
]
路由和视图代码:
#主urls.py
path('article/',include('article.urls',namespace='article'))
#应用urls.py,创建的应用这个文件不会自动生成,需要我们新建
fromdjango.urlsimportpath
from.importviews
app_name='article'
urlpatterns=[
path('index/',views.index,name='index')
]
#视图views.py
fromdjango.shortcutsimportrender
defindex(request):
returnrender(request,'index.html')#使用render渲染模板
模板文件,项目根目录下templates目录(若没有自动生成,则手工新建此文件夹)下新建index.html模板文件。
文章首页文章首页
查看效果:
使用render函数将模板成功渲染出来了。
3. 模板文件查找路径
在项目的settings.py配置文件中,有一个TEMPLATES配置。
TEMPLATES=[
{
#模板引擎,就是Django内置的模板引擎,
#若要配置为Jinja2:django.template.backends.jinja2.Jinja2
'BACKEND':'django.template.backends.django.DjangoTemplates',
#BASE_DIR,项目根目录路径下的templates查找
#'DIRS':[os.path.join(BASE_DIR,'templates')]#Django2中使用
'DIRS':[BASE_DIR/'templates'],#Django3中使用
,
#是否从app应用下的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',
],
},
},
]
这个配置包含了模板引擎的配置,这个配置包含了模板引擎的配置,模板查找路径的配置,模板上下文的配置等,模板路径可以2个地方配置。
DIRS:这是一个列表,在这个列表中可以存放所有的模板路径,以后在视图中使用render渲染模板时,就会从这个列表的路径中查找模板。
APP_DIRS:默认为True,这个表示已经在INSTALLED_APPS文件中注册过的应用app下的templates目录下查找模板文件。
查找顺序:比如代码render(request,'index.html'),先会在DIRS这个列表中依次查找路径下有没有这个模板,如果有,就返回,如果没有,则会先检查当前视图所处的app是否已经安装,那么就先在当前app下的templates目录下查找模板,如果没有找到,就会去其他注册的app中继续查找,如果所有路径下都没有找到,则会抛出TemplateDoesNotExist。
二、DTL模板语法
1. 模板变量
我们想要将后台数据渲染到页面上,这就需要用到模板变量。
#主urls.py
path('article/',include('article.urls',namespace='article'))
#应用urls.py
path('index/',views.index,name='index')
#视图views.py
fromdjango.shortcutsimportrender
classArticle:
def__init__(self,title):
self.title=title
defindex(request):
context={
'msg':'模板变量',#字符串,
'article':Article('Django框架之模板文件'),#实例一个对象,
'author':{'name':'admin'},#一个字典
'tag':['python入门','python进阶','数据库']#列表或元组
}
returnrender(request,'index.html',context=context)#传入一个字典
模板文件:
文章首页文章首页{{msg}}
{{article.title}}
作者:{{ author.name }}
{{tag.0}}
{{tag.1}}{{tag.2}}
效果:
在模板中使用变量:语法:{{变量名}} 1)命名由字母和数字以及下划线组成,不能有空格和标点符号。2)不要和python或django关键字重名。原因:如果data是一个字典,那么访问data.items将会访问data这个字典的key名为items的值,而不会访问字典的items方法。
2. 模板标签
标签语法:{% 标签名称 %} {% 结束标签名称 %}。
例:{%tag%} {%endtag%}
2.1 if标签
if标签相当于python中的if语句,有elif和else相对应,可以使用and、or、in、not、==、!=、<=、>=、is、is not,来进行判断。
视图views.py:
defindex(request):
age=random.randint(6,20)#随机生成6-20的整数
context={
'age':age
}
returnrender(request,'index.html',context=context)
模板文件:
文章首页年龄:{{age}},适合读{%ifage>=18%}
【大学】书籍
{%elif12
再刷新一次:
我们还可以使用ifequal/ifnotequal来比较两个值是否相等,如:
{% ifequal price 0 %}{% else %}{% endifequal %}
2.2 for...in...标签
for标签相当于python中的for循环,可以遍历列表、元组、字符串、字典等一切可以遍历的对象。
#视图views.py
defindex(request):
context={
'articles':[#列表
'21天学会Python',
'C++从入门到入土',
'Mysql从入门到跑路'
],
'author':{#字典
'name':'老P',
'age':18,
'sex':'boy'
},
'artile_details':[
{'title':'21天学会Python','author':'小P','words':1000},
{'title':'C++从入门到入土','author':'中P','words':2000},
{'title':'Mysql从入门到跑路','author':'老P','words':3000}
]
}
returnrender(request,'index.html',context=context)
模板文件:
文章首页{% for article in articles %}{{ article }}{% endfor %}获取字典键:{% for key in author.keys %}{{ key }}{% endfor %}获取字典值:{% for value in author.values %}{{ value }}{% endfor %}获取字典键值对:{% for key, value in author.items %}{{ key }}:{{ value }}{% endfor %}文章信息列表:序号标题作者字数{% for article_detail in artile_details %}
{% if forloop.first %} {% elif forloop.last %} {% else %}{% endif %}{{ forloop.counter }}{{ article_detail.title }}{{ article_detail.author }}{{ article_detail.words }}{% endfor %}
还有个for...in...empty,在遍历的时候如果需要遍历的对象没有为空,则执行empty下的操作。
{% for comment in comments %}
{{ comment }}
{# 在for循环之前检查列表大小是常见的,当列表为空的时候给出特别提示,这是常见的,所以for支持可选empry来当为空时输出 #}
{% empty %} 还没有评论~~~
{% endfor %}
有时候可能在页面上要用上循环几次,可以用:
{% for item in 'x'|ljust:'4' %} 循环四次
{%endfor %}
2.3 with标签
使用一个简单地名字缓存一个复杂的变量,当你需要使用一个代价较大的方法(比如访问数据库)很多次的时候这是非常有用的。
文章首页{{ title }}
{% with t1=title %} {{ t1 }}
{% endwith %}
{% with title as t2%} {{ t2 }}
{% endwith %}
注意:定义的变量只能在with语句块中使用,在with语句块外面使用取不到这个变量。
2.4 url标签
在模板中,经常要写一些超链接,比如a标签中需要定义href属性,当然如果通过硬编码的方式直接将这个url写死也是可以,但是不便于以后维护,比如需要修改url地址,那涉及到的地方都要修改,因此建议使用这种反转的方式来实现,类似于django中的reverse一样。
#应用urls.py
fromdjango.urlsimportpath
from.importviews
app_name='article'
urlpatterns=[
path('index/',views.index,name='index'),
path('book/',views.book,name='book'),
path('movie/',views.movie,name='movie'),
path('city/',views.city,name='city'),
path('book/hot/',views.hot_book,name='hot_book')
]
#视图views.py
fromdjango.shortcutsimportrender,HttpResponse
defindex(request):
returnrender(request,'index.html')
defbook(request):
returnHttpResponse('读书页面')
defmovie(request):
returnHttpResponse('电影页面')
defcity(request):
returnHttpResponse('同城页面')
defhot_book(request,book_id):
returnHttpResponse('最热门文章:%d'%book_id)
模板文件:
文章首页首页读书电影同城最火文章
2.5 autoescape标签
DTL中默认已经开启了自动转义,会将哪些特殊字符进行转义,比如会将<<>转义成<<>等。
defindex(request):
comment_info='个人博客网站:全民python'
context={
'info':comment_info
}
returnrender(request,'index.html',context=context)
模板文件:
个人博客网站:全民python{{info}}
{%autoescapeoff%}
{{info}}
{%endautoescape%}
如果你不知道自己在干什么,最好是使用自动转义,这样网站才不容易出现XSS漏洞(比如有些网站进行评论的时候,发一些含恶意的js代码,如果不进行自动转义会进行渲染,而不会做成普通的字符串),比如我个人博客的评论就处理了。如果是可信用的,可以关闭自动转义,比如我的文章内容是只允许我个人发表,是可信任的,所以我直接关闭。后面可以通过过滤器safe类似处理。
2.6 verbatim标签
默认在DTL模板中是会去解析那些特殊字符的,比如{% %}和{{ }}等,如果我们在某个代码片段不想使用DTL的解析,那么我们可以将这段代码放在verbatim标签中。
#视图
defindex(request):
returnrender(request,'index.html')
#模板{%ifmsg%}
{{msg}}
{%else%}
没消息
{%endif%}
{%verbatim%}
{%ifmsg%}
{{msg}}
{%endif%}
{%endverbatim%}
这个主要是用在,有些前端模板语法layui还有vue中也使用{{}}来表示变量,这些与DTL类似,这样就容易引起混淆,我们可以使用这个标签,来屏蔽掉DTL的解析,而让前端模板去解析。
2.7 注释标签
我们在HTML中经常使用来进行注释,在Django模板中,我们还可以使用其他注释。
{# 被注释的内容 #}:将中间的内容注释掉。只能单行注释。
{% comment %}被注释的内容{% endcomment %}:可以多行注释。
这种注释,当我们查看网页元素的时候是看不到的,即没有被渲染,而还是可以看到原样字符串的。
2.8 自定义简单标签
1)首先,需要添加一个templatetags的文件夹, 自定义标签必须处在已经安装了的app(INSTALLED_APPS注册了)中的一个名叫templatetags的包中。
templatetags 文件夹名字不能修改,这是django规定的。
myproject
|——myproject
|——__init__.py
|——asgi.py
|——settings.py
|——urls.py
|——wsgi.py
|——templates
|——myapp
|——migrations
|——templatetags
|——__init__.py
|——custom_tags.py
|——manage.py
2)在templatetags下添加一个python文件,如我这里创建一个custom_tags.py文件,在文件中添加对应的自定义标签。
fromdjangoimporttemplate
#register的名字是固定的,不可改变
register=template.Library()
#使用装饰器注册自定义标签
@register.simple_tag
defcurr_date(args):#args可传参数,根据实际需求而定
returndatetime.datetime.now().strftime(args)
3)在要使用自定义标签的HTML模板中导入和使用自定义标签文件:
{# 加载自定义标签所在的文件名,由于templatetags的文件名是固定的,django可以直接找到过自定义标签文件所在的位置 #}
{% load custom_tags %}自定义标签时间日期:{% curr_date "%Y-%m-%d"%}
我们再来定义简单标签article/templatetags/menu_tags.py:
fromdjangoimporttemplate
#register的名字是固定的,不可改变
register=template.Library()
@register.simple_tag
defmy_menu():
menu_list=['首页','项目实战','每日一练']
returnmenu_list
模板文件templates/article/my_menu.html:
自定义简单标签-----------菜单栏--------------{% load menu_tags %}
{% my_menu as menus %} {% for menu in menus %} {# 企图使用 {% for menu in my_menu %} 是没效果的 #}{{menu}}{% endfor %}
视图渲染views.py:
deftest(request):
returnrender(request,'article/my_menu.html')
2.9 自定义包含标签inclusion_tag
一种比较普遍的tag类型只是渲染其他模块显示下的内容,这样的类型叫做inclusion_tag,常用的模板标签是通过渲染其他模板显示数据的。
inclusion_tag作用:创建一个动态页面文件a.html,这个页面可以在另外一个页面b.html中被调用,实现这个页面a中有的功能。
例如,上面一个导航页面my_menu.html,基本在每个页面中都要包含导航,如我的个人博客一样:
那要怎么样呢?
例如,我们在首页模板中,先试下用include来引入导航模板看看(include这个后面具体学习,这里只演示作用)。
与上面自定义简单标签类似,在自定义标签文件里面自定义包含标签:
fromdjangoimporttemplate
fromarticle.modelsimportColumn
#register的名字是固定的,不可改变
register=template.Library()
#使用装饰器注册自定义包含标签
@register.inclusion_tag('article/my_menu.html')#将返回值传给my_menu.html去,可以定义name,否则使用函数名
defmy_menu():
#menus=['首页','项目实战','每日一练']
menus=Column.objects.all()
return{'menus':menus}
my_menu.html:
自定义包含标签{% for menu in menus %}{{menu}}{% endfor %}
调用的html页面文件:
首页{% load menu_tags %}
{% my_menu %} 首页
视图渲染:
deftest(request):
returnrender(request,'article/index.html')
2.10 人性化语义标签
除了上述功能性标签外, Django 还提供了很多辅助性标签,这些标签只是为了使变量输 出变得更加可读,下面对这些标签进行简单介绍。首先为了使用这些标签,需要在INSTALLED_APPS 中注册django .contrib.humanize, 然后在模板中引用humanize:{% raw %}{% load humanize % }{% endraw %}
apnumber
将数字1 ~ 9 转换为英文单词,但是其他数字不转换,如数字10 将被原样输出。示例:
数字1被转换为one;
数字2被转换为two;
数字10仍显示10;
如果当前工程语言是中文的话,数字将会被转换为对应的汉字,例如:
{%raw%}
{{1|apnumber}}
{{2|apnumber}}
{{5|apnurnber}}
{%endraw%}
如果当前工程语言是中文的话,数字将会被转换为对应的汉字,例如:
输出:
一
二
五
intcomma
输出以逗号分隔的数字,如4500 输出4,500, 4500.2 输出4,500.2 。
intword
以文字形式输出数字,如1000000 输出“ 1.0 million ”, 1200000 输出“ 1,2 Million ” 。对于中文系统,将会输出对应的中文,如1200000 输出" 1.2 百万” 。
naturalday
将当前日期以及前后一天输出为today 、yesterday 和tomorrow ,而中文系统分别输出 “今天”“昨天”和“明天” 。
naturaltime
对于日期时间格式,时间值与系统当前时间比较,然后输出结果。如当前时间输出 “ now ”, 29 秒前输出“ 29 sec onds ago ” 。如果使用naturaltime 输出今天、昨天、明天的话, 就会变成“现在”“ 23 小时·以后”“ 1 日之前” 。
ordinal
将数字转换为序数,如l 输出“ 1 st ”;2 输出“ 2nd ”;3 输出“ 3rd ” 。注意此时中文与 英文的输出一样。
3. 模板过滤器
在模板中,有时候需要对一些数据进行处理以后才能使用,一般在Python中我们是通过函数的形式来完成的,因为在DTL中,不支持函数的调用形式(),因此在模板中,则是通过过滤器来实现的,过滤器使用的是|来使用。语法:
{{变量名|过滤器名:传给过滤器的参数}}
3.1 常用过滤器
比如使用date过滤器。
#视图
fromdatetimeimportdatetime
defindex(request):
now_time=datetime.now()
context={
'now_time':now_time
}
returnrender(request,'index.html',context=context)
#模板文件文章首页{{now_time}}
{{now_time|date:'Y-m-dH:i:s'}}
date时间过滤器格式:
格式字符描述示例Y4位数的年1999y2位数的年99m2位数的月01,09n1位数的月1,9,12d2位数的日01,09,31j1位数的日1,9,31g12小时制的一位数的小时1,9,12G24小时制的一位数小时0,8,23h12小时制的两位数的小时01,09,12H24小时制的两位数的小时01,13,24i分钟00-59s秒00-59
django常用过滤器:
add:字符串相加,数字相加,列表相加,如果失败,将会返回一个空字符串。default:提供一个默认值,在这个值被django认为是False的时候使用。比如:空字符串、None、[]、{}等。区别于default_if_none,这个只有在变量为None的时候才使用默认值。first:返回列表中的第一个值。last:返回列表中的最后一个值。date:格式化日期和时间。time:格式化时间。join:跟python中的join一样的用法。length:返回字符串或者是数组的长度。length_is:字符串或者是数组的长度是否是指定的值。lower:把所有字符串都编程小写。truncatechars:根据后面给的参数,截断字符,如果超过了用…表示。{{value|truncatechars:5}},如果value是等于北京欢迎您,那么输出的结果是北京...,为啥不是北京欢迎您...呢?因为三个点也占了三个字符,所以北京 + 三个点的字符长度就是5。truncatewords:类似truncatechars,不过不会切割html标签,{{value|truncatewords:5}},如果value是等于
北京欢迎您
,那么输出的结果是
北京...
,capfirst:首字母大写。slice:切割列表。用法跟python中的切片操作是一样的,区间是前闭合后开放。striptags:去掉所有的html标签。safe:关闭变量的自动转义,解析html标签。floatformat:浮点数格式化。更多可以查询官方文档:https://yiyibooks.cn/xx/Django_1.11.6/ref/templates/builtins.html英文:https://docs.djangoproject.com/en/1.11/ref/templates/builtins/
过滤器总结:1、作用:对变量进行过滤。在真正渲染出来之前,过滤器会根据功能处理好变量,然后得出结果后再替换掉原来的变量展示出来。2、语法:{{greeting|lower}},变量和过滤器中间使用管道符号”|”进行使用。3、可以通过管道符号进行链式调用,比如实现一个功能,先把所有字符变成小写,把第一个字符转换成大写,如{{message|lower|capfirst}}
4、过滤器可以使用参数,在过滤器名称后面使用冒号”:”再加上参数,比如要把一个字符串中所有的空格去掉,则可以使用cut过滤器,代码如下{{message|cut:" "}},冒号和参数之间不能有任何空格,一定要紧挨着。
3.2 自定义过滤器
虽然DTL给我们内置了许多好用的过滤器,但是有些时候还是不能满足我们的需求,因此Django给我们提供了一个接口,可以让我们自定义过滤器,实现自己的需求。
步骤:
1、首先在某个应用app中,创建一个python包,叫做templatetags,注意名字不能改动,不然找不到。
2、在这个templatetags包下创建一个python文件用来存储过滤器。
3、在新建的python文件中,定义过滤器(也就是函数),这个函数的第一个参数永远是被过滤器的那个值,并且如果在使用过滤器的时候传递参数,那么还可以定义另外一个参数,但是过滤器最多只能有2个参数。
4、自定义完过滤器,要使用django.template.Library.filter进行注册。
5、过滤器所在app所在app需要在settings.py中进行注册。
6、在模板中使用load标签加载过滤器所在的python包。
7、在模板中使用自定义的过滤器。
我们来实现一个朋友圈,或者文章发表时间显示的过滤器:
#自定义过滤器date_filter.py
fromdjangoimporttemplate
fromdatetimeimportdatetime,timedelta
#将注册类实例化为register对象
# register = template.Library()创建一个全局register变量,它是用来注册你自定义标签和过滤器的,只有向系统注册过的tags,系统才认得你。
#register不能做任何修改,一旦修改,该包就无法引用
register=template.Library()
#使用装饰器注册自定义过滤器
@register.filter
defdate_filter(value):
#判断一下,是不是时间日期类型
ifnotisinstance(value,datetime):
returnvalue
now=datetime.now()+timedelta(hours=8)#将UTC时间转为本地时间
#total_seconds()是获取两个时间之间的总差
timestamp=(now-value).total_seconds()
iftimestamp=60andsec文章首页{{public_time|date_filter}}
4. 模板结构化优化
4.1 引入模板
有时候一些代码是在许多模板中都用到的,如果每次都重复的去拷贝代码那肯定不符合项目的规范,一般我们可以把这些重复性的代码抽取出来,就类似于Python的函数一样,以后想要使用这些代码的时候,就通过include包含进来,这个标签就是include。比如大多数网页都有顶部,中间,底部,可能进入任何页面顶部和底部都是一样的,只有中间部分内容不同,这个时候顶部和底部,我们就可以通过include包含起来。
#顶部,header.html首页Python教程PythonWeb开发Python爬虫用户名:{{username}}#底部,footer.html2019全民python |
粤ICP备18143893号 |
#首页,index.html
文章首页{%include'header.html'withusername='全民python'%}
这是中间内容
{%include'footer.html'%}
视图:
defindex(request):
returnrender(request,'index.html')
我们使用include标签时,如果引入的html代码中需要传入变量,则需要在所引入的view视图中获取变量,如果引入的html代码中的变量是一个公共变量,则需要重复获取N次,使用自定义包含标签inclusion_tag,可以在定义文件中获取一次即可。
templates/article/my_menu.html
自定义简单标签-----------菜单栏--------------{% load menu_tags %}
{% my_menu as menus %} {% for menu in menus %} {# 企图使用 {% for menu in my_menu %} 是没效果的 #}{{menu}}{% endfor %}
article/templatetags/menu_tags.py
fromdjangoimporttemplate
fromarticle.modelsimportColumn
#register的名字是固定的,不可改变
register=template.Library()
@register.simple_tag
defmy_menu():
#menu_list=['首页','项目实战','每日一练']
menu_list=Column.objects.all()
returnmenu_list
templates/article/index.html:
首页{% include 'article/my_menu.html' %}首页
两者感觉效果一样。
4.2 模板继承
对于模板的重复利用,除了使用include标签引入,还有另外种方式来实现,那就是模板继承。模板继承类似于Python中的类,在父类中可以先定义好一些变量和方法,然后在子类中实现,模板继承也可以在父模板中先定义好一些子模板需要用到的代码,然后子模板直接继承就可以了,并且因为子模板肯定有自己的不同代码,因此可以在父模板中定义一个block接口,然后子模板再去实现。
我们将上面那个例子,使用模板继承改写下,将固定不变的顶部和底部,放在父模板中,中间变动的部分,子模板去实现。
{% block title %}全民python{% endblock %}*{
margin: 0;
padding: 0;
}
header,footer{
background: black;
height: 60px;
width: 100%;
color: white;
text-align: center;
line-height: 40px;
}
footer{
height: 90px;
line-height: 90px;
position: absolute;
bottom: 0;
}
ul li{
list-style: none;
float: left;
margin: 20px;
}
#loginbox{
width: 400px;
height: 200px;
border: 1px solid red;
margin: 90px auto;
text-align: center;
}首页编程语言项目实战每日一学{% block content %}
这是子模板自己实现的部分
{% endblock %}这是footer部分
{% extends 'base.html' %}
{% block title %}{{ block.super }}-登录界面{% endblock %}
{% block content %}登录界面帐 号:密 码:{% endblock %}
视图函数:
defindex(request):
returnrender(request,'index.html')
效果展示:
总结:
模板继承使用extends标签实现,通过使用block来给子模板开放接口;
extends必须是模板中第一个出现的标签;
子模板中的内容必须放在父模板定义好的block中,否则将不会被渲染;
如果在某个block中需要使用父模板的内容,那么可以使用{{ block.super }}来继承;
子模板决定替换的block块,无须关注其它部分,没有定义的块即不替换,直接使用父模板的block块;
除了在开始的地方定义名字,我们还可以在结束的时候定义名字,如{% block title %}{% endblock %},这样在大型模板中显得尤其有用,能让我们快速看到block所包含的开始和结束。
模板引入与自定义inclusion_tag的区别:模板导入的页面内容是静态的、不变的,而通过自定义inclusion_tag导入的页面文件可以是动态的,可动性自己掌控。
5. 加载静态文件
在一个网页中,不仅仅只有一个html,还需要css样式,js脚本以及一些图片,因此在DTL中加载静态文件是一个必须要解决的问题,在DTL中,使用static标签来加载静态文件,要使用static标签,首先需要{% load static %}。
1、首先,settings.py文件中,确保django.contrib.staticfiles已经添加到INSTALLED_APPS中。
INSTALLED_APPS=[
...
'django.contrib.staticfiles',
...
]
2、设置DEBUG调试模式。
#在settings.py中,默认值是DEBUG=True
DEBUG=True
当我们在开发django应用时如果设置了 DEBUG = True,那么django便会自动帮我们对静态文件进行路由;但是当我们设置DEBUG = False后,静态文件找不到了,「img、css、js」都提示404,无法准确的访问 static 静态文件。
3、在开发模式下(Debug=True)时,访问静态文件有下面两种情况:1)在已注册的应用app下创建一个静态文件夹名称static,然后再再这个static目录下创建于app同名的 文件夹用于存放静态文件(避免不同应用app,静态文件名字一样,造成冲突)。
Django将通过 django.contrib.staticfiles在每个app的static文件夹中为我们自动查找这些静态文件。
2)如果有些静态文件和应用没什么太大的关系,我们可以在项目根目录下再创建static目录,这个时候我们还需要在settings.py文件配置添加STATICFILES_DIRS,以后DTL就会在这个列表的路径中查找静态文件。
#django2.x方式
#STATICFILES_DIRS=[os.path.join(BASE_DIR,'static')]#这里指静态文件保存哪个目录下,这个“static”指目录名
#django3.x方式
#一般用来设置通用的静态资源,对应的目录不放在APP下,而是放在Project下,例如:
STATICFILES_DIRS=[BASE_DIR/'static']
然后再像上面一样加载静态文件使用,一般直接在根项目下新建static,然后在下面新建不同以应用名称命名的目录。
STATICFILES_DIRS告诉django,首先到STATICFILES_DIRS里面寻找静态文件,其次再到各个app的static文件夹里面找(注意,django查找静态文件是惰性查找,查找到第一个,就停止查找了)。
4、只有在生产模式(Debug=False)时,STATIC_ROOT设置才生效。
STATIC_ROOT 是在部署静态文件时(pyhton manage.py collectstatic)所有的静态文静聚合的目录,STATIC_ROOT要写成绝对地址,如下例子STATIC_ROOT设为根目录下的static_new文件,而STATICFILES_DIRS使用根目录下的static目录。
#STATICFILES_DIRS=[os.path.join(BASE_DIR,'static')]#这里指静态文件保存哪个路径,这个“static”指目录名
STATICFILES_DIRS=[BASE_DIR/'static']
ifnotDEBUG:
#STATIC_ROOT=os.path.join(BASE_DIR,"static_new")#使用collectstatic后收集的静态文件的存放绝对路径
STATIC_ROOT=[BASE_DIR/'static_new']
当部署项目时,在终端输入:
#django会把所有的static文件都复制到STATIC_ROOT文件夹下
pythonmanage.pycollectstatic
然后可以看到根目录下有创建了一个static_new文件夹,里面有STATICFILES_DIRS里设置的文件夹里的静态文件,同时也有各app下static文件夹里的静态文件。
在部署模式(Debug=False)时,Django会从STATIC_ROOT设置的文件夹读取静态文件,而不再从STATICFILES_DIRS设置的文件夹或app下的static文件夹。所以在(Debug=False)时需要先python manage.py collectstatic同步一下静态文件。
说明:真实上生产,静态文件可能就交给nginx了,配置好即可,就不会再从django里面读取静态文件了。具体后续我们会细说
5、上面我们已经配置好静态文件了,那怎么样访问呢?
如果在浏览器是访问,不可能输入你的静态文件的本地绝对地址吧,比如我的一种图片的本地地址为 /root/src/project/QmpythonBlog/static/image/article/article_cover.png,那我们不可能
在浏览器上直接输入:http://127.0.0.1:5044/root/src/project/QmpythonBlog/static/image/article/article_cover.png 这样子,浏览器会报错, 没有该页面,那么django是如何让浏览器也可以访问服务器上的静态文件呢?
上面已经说了,直接访问服务器本地的地址是不行的,那就需要一个映射。
django利用STATIC_URL来让浏览器可以直接访问静态文件。
settings.py文件中确保配置了STATIC_URL,STATIC_URL用于引用STATICFILES_DIRS或STATIC_ROOT所指向的静态文件。
当我们创建Django项目的时候,在setting.py中默认就已经设置了。
#静态文件存储,一般是我们的JS、css、系统的图片文件等。
#这个“static”指访问静态文件,引入时用的别名
#通过http://127.0.0.1/static/***就可以访问相关的静态文件了。
STATIC_URL='/static/'
例如:在应用user下新建static目录,再在static下新建user目录:
视图:
#user应用下的视图views.py
defindex(request):
returnrender(request,'user/index.html')
模板文件:
用户登录首页用户界面
但是上面要写绝对路径不方便,那我们可以通过static标签来加载静态文件:
{% load static %}
用户登录首页用户界面{# #}
{% static %}这个模板变量使用的就是STATIC_URL的值,例如默认的STATIC_URL值为/static/,那么上面模板变量引用后的值便为/static/开头的地址。
那么STATIC_URL又是怎么能正确的找到静态文件地址的呢。
1)在开发模式下(Debug=True)时,使用的是STATICFILES_DIRS和app下的static中的静态文件,Django有默认的对STATIC_URL路由能自动找到放在里面的静态文件。
2)在部署模式(Debug=False)时,使用的是STATIC_ROOT中的静态文件,此时则没有了默认的对STATIC_URL的路由,需要自己在project的urls.py中写一个,将STATIC_URL开头的请求转发到STATIC_ROOT中进行查找。
fromdjango.views.staticimportserve
fromdjango.conf.urls.staticimportstatic
urlpatterns=[
re_path(r'^static/(P.*)$',serve,{'document_root':settings.STATIC_ROOT},name='static'),
]
在部署生产环境时(Debug=False),通常使用另外一种方法就是使用Nginx来实现。
如果你在项目中用到了static这个模板标签,那一定要将nginx(或其他)服务器的/static配置到与STATIC_ROOT一致!(如果执行了收集的话)
可以参考django部署配置:Centos7中使用Nginx+uWSGI+Django部署Web项目
此时我们在应用中加载静态文件的话就只需要这么来写了,需要将STATIC_URL设为/static/,以img加载为例:
额外知识点:
1、如果不想在模板文件中每次都通过{% load static %}加载静态文件。
TEMPLATES=[
{
'BACKEND':'django.template.backends.django.DjangoTemplates',
#'DIRS':[os.path.join(BASE_DIR,'templates')]#django2写法
'DIRS':[BASE_DIR/'templates'],#django3写法
,
'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']#添加这一行,就会将static当作内置的标签,无需再手动load
},
},
]
备注:一般个人倾向于,直接将static文件放到项目根目录下,下面再根据app名字进行分门别类。
相关推荐
- Linux 系统启动完整流程
-
一、启动系统流程简介如上图,简述系统启动的大概流程:1:硬件引导UEFi或BIOS初始化,运行POST开机自检2:grub2引导阶段系统固件会从MBR中读取启动加载器,然后将控制权交给启动加载器GRU...
- 超专业解析!10分钟带你搞懂Linux中直接I/O原理
-
我们先看一张图:这张图大体上描述了Linux系统上,应用程序对磁盘上的文件进行读写时,从上到下经历了哪些事情。这篇文章就以这张图为基础,介绍Linux在I/O上做了哪些事情。文件系统什么是...
- linux入门系列12--磁盘管理之分区、格式化与挂载
-
前面系列文章讲解了VI编辑器、常用命令、防火墙及网络服务管理,本篇将讲解磁盘管理相关知识。本文将会介绍大量的Linux命令,其中有一部分在“linux入门系列5--新手必会的linux命令”一文中已经...
- Linux环境下如何设置多个交叉编译工具链?
-
常见的Linux操作系统都可以通过包管理器安装交叉编译工具链,比如Ubuntu环境下使用如下命令安装gcc交叉编译器:sudoapt-getinstallgcc-arm-linux-gnueab...
- 可算是有文章,把Linux零拷贝技术讲透彻了
-
阅读本文大概需要6.0分钟。作者:卡巴拉的树链接:https://dwz.cn/BaQWWtmh本文探讨Linux中主要的几种零拷贝技术以及零拷贝技术适用的场景。为了迅速建立起零拷贝的概念...
- linux软链接的创建、删除和更新
-
大家都知道,有的时候,我们为了省下空间,都会使用链接的方式来进行引用操作。同样的,在系统级别也有。在Windows系列中,我们称其为快捷方式,在Linux中我们称其为链接(基本上都差不多了,其中可能...
- Linux 中最容易被黑客动手脚的关键目录
-
在Linux系统中,黑客攻击后常会针对关键目录和文件进行修改以实现持久化、提权或隐藏恶意活动。本文介绍下黑客最常修改的目录及其手法。一、/etc目录关键文件有:/etc/passwd和/et...
- linux之间传文件命令之Rsync傻瓜式教程
-
1.前言linux之间传文件命令用什么命令?本文介绍一种最常用,也是功能强大的文件同步和传输工具Rsync,本文提供详细傻瓜式教程。在本教程中,我们将通过实际使用案例和最常见的rsync选项的详细说...
- Linux下删除目录符号链接的方法
-
技术背景在Linux系统中,符号链接(symlink)是一种特殊的文件,它指向另一个文件或目录。有时候,我们可能需要删除符号链接,但保留其指向的目标目录。然而,在删除符号链接时可能会遇到一些问题,例如...
- 阿里云国际站注册教程:aa云服务器怎么远程链接?
-
在全球化的今天,互联网带给我们无以计数的便利,而云服务器则是其中的重要基础设施之一。这篇文章将围绕阿里云国际站注册、aa云服务器如何远程链接,以及服务器安全防护如Ddos防火墙、网站应用防护waf防火...
- Linux 5.16 网络子系统大范围升级 多个新适配器驱动加入
-
Linux在数据中心中占主导地位,因此每个内核升级周期的网络子系统变化仍然相当活跃。Linux5.16也不例外,周一最新与网络相关的更新加入了大量的驱动和新规范的支持。一个较新硬件的驱动是Realt...
- 搭建局域网文件共享服务(Samba),手机电脑都能看喜欢的影视剧
-
作为一名影视爱好者,为了方便地观看自己喜欢的影视作品,在家里搞一个专门用来存放电影的服务器是有必要的。蚁哥选则用一台Ubuntu系统的电脑做为服务器,共享影音文件,其他同一个局域网内的电脑或手机可以...
- 分享一个实用脚本—centos7系统巡检
-
概述这周闲得慌,就根据需求写了差不多20个脚本(部分是之前分享过的做了一些改进),今天主要分享一个给平时运维人员用的centos7系统巡检的脚本,或者排查问题检查系统情况也可以用..实用脚本#!/bi...
- Linux 中创建符号链接的方法
-
技术背景在Linux系统里,符号链接(SymbolicLink),也被叫做软链接(SoftLink),是一种特殊的文件,它指向另一个文件或者目录。符号链接为文件和目录的管理带来了极大的便利,比...
- 一文掌握 Linux 符号链接
-
符号链接(SymbolicLink),通常被称为“软链接”,是Linux文件系统中一种强大而灵活的工具。它允许用户创建指向文件或目录的“快捷方式”,不仅简化了文件管理,还在系统配置、软件开发和日...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- skip-name-resolve (63)
- linuxlink (65)
- httperror403.14-forbidden (63)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)