欢迎来到Cecilia陈的博客

孤独,是人一生最好的修行。

06 Django 模板层

一、模板层简介

在视图层中我们提到,浏览器发送的请求信息会转发给视图函数进行处理,而视图函数在经过一系列处理后必须要有返回信息给浏览器。如果我们 要返回html标签、css等数据给浏览器进行渲染,我们可以在视图函数中这么做

import datetime
def current_datetime(request): 
    now = datetime.datetime.now()   
    # 这里HttpResponse可以将html标签自动的转义,然后发给浏览器
    html = "<html><body>It is now %s.</body></html>" % now   
    return HttpResponse(html)

上例所示,我们直接将HTML代码放到视图函数里,然后进行返回,这可以使我们 很直观地看清楚浏览器从发送请求到看到前端界面内容的这个过程中视图函数的 基本工作原理,但是这种将前端代码与后端代码耦合到了一起开发方式,会存在 以下问题

1、程序的可维护性与可扩展性问题 前端界面一旦需要重新设计、修改,则必须对后端的Python代码进行相应的修改。 然而前端界面的修改往往比后端 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更前端界面的设计,那将会方 便得多。 
 
2、开发效率问题 Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将它们分配给不同的人员(甚至不同 部门)来完成。 专门的程序员去编写 Python代码、专门的设计人员去制作模板,这两项工作同时进行,效率才是高 的。 

基于上述原因,将前端页面和Python的代码分离是一种不错的开发模式。 为此 Django专门提供了模板系统 (Template System,即模板层)来实现这种模式.

二、django的模板=HTML代码+模板语法

存放于templates目录下的html文件称之为模板文件,如果我们想要返回的html页 面中的数据是动态的,那么必须在html页面中嵌入变量,这便用到了django的模 板语法,具体来说,django的模板语法有以下重点

一、变量:{{ 变量名 }}  
	1.1 深度查询:句点符的应用 
    1.2 过滤器 
二、标签:{% 标签名 %} 
三、自定义标签和过滤器
四、模板的导入和继承

三、模板语法之变量

3.1 变量的基本使用

如果html代码中的数据不是固定死的,而是动态变化的,则必须在html中嵌入变 量,为此,模板语法提供了变量的概念,允许我们在html代码中嵌入变量,我们只需要在视图函数中用render方法为html文件中指定的变量赋值即可,具体用法如下:

# view.py 视图文件
def test(request):
    # 传给模板文件的变量之可以是任意python类型,如下
    a = 123 # 整型
    b = 123.456 # 浮点型
    c = 'abc' # 字符串
    d  = [1,2,3,4,5] # 列表
    e = (1,2,3) # 元组
    f = {4,5,6,7,8} # 集合
    g = {'user':'xichen','pwd':123,'hobbies':['run','rad']} # 字典
    t = True # 布尔值

    def func(): # 这是函数
        return '我是xichen'
	
    # return render(request,'test1.html',{'a':a,'b':b,'c':c,'d':d.....})
    # 1、render函数的第三个参数包含了要传给模板的变量值,是一个字典类型,该字典中的key必须与模板文件中 的变量名相对应,render函数会去templates目录下找到模板文件,然后根据字典中的key对应到模板文件中的变量名 进行赋值操作,后将赋值后的模板文件内容返回给浏览器  
    
    # 2.这里将当前名称空间里的所有变量的值都传给模板文件,还有用字典的方式,用local更方便
    return render(request,'test1.html',locals())
# html模板
<!DOCTYPE html> 
<html lang="en">
<head>     
	<meta charset="UTF-8">
    <title>Title</title> </head> 
<body>
    <p>我是整型a:{{a}}</p>
    <p>我是浮点型b:{{b}}</p>
    <p>我是字符串c:{{c}}</p>
    <p>我是列表d:{{d}}</p>
    <p>我是元组e:{{e}}</p>
    <p>我是集合f:{{f}}</p>
    <p>我是字典g:{{g}}</p>
    <p>我是字典g的hobbies字段:{{g.hobbies}}</p>
    <p>我是字典g的hobbies字段:{{g.hobbies.0}}</p>
    <p>我是字典g的hobbies字段:{{g.hobbies.1}}</p>
    <p>我是布尔值t:{{t}}</p>
    <p>我是函数func:{{func}}</p>
    
    <!--句点符不仅可以引用容器类元素,也可以引用对象-->
    <p>我是类MyInfo:{{my_obj}}</p> <!--这里是类对象的地址-->
    <p>我是类MyInfo对象的名字:{{my_obj.name}}</p>
    <p>我是类MyInfo对象的密码:{{my_obj.pwd}}</p>
</body>
</html>

总结1:在视图层中给模板文件传函数名时,在模板文件中接收的函数名会自动的加括号调用这个函数,并且获取到执行函数的返回值,但是不支持带参数的函数。

总结2:在获取容器类内部的数据时,只能用.点的方式取值,其他方式都不支持,另外容器类型的数据不管里面嵌套了多少层,都继续用点的方式,点的时候,可以直接跟容器类型元素的索引

总结3:以上总结两点里面的点的方式,.称之为句点符:也就是句点符的使用,可以具体的渠道某一个容器类元素最底层的值

3.2 过滤器

过滤器类似于python的内置函数,用来把视图传入的变量值加以修饰后再显示, 具体语法如下:

{ 变量1|过滤器名:传给过滤器的参数 }

常用内置过滤器

1.add 相加
{{a|add:b}}
add左边的参数是第一个过滤器的第一个参数,add右边的参数是过滤器的第二个参数
函义:将a,b两个变量的值相加
注意:如果a,b两个参数的类型都是数值型,就进行数值相加
	 如果a,b两个参数是字符型,那就将两个参数相拼接
     如果a,b两个参数是不同类型的,那就返回空


# view.py文件
def test(request):
    a = 1
    b = 2
    return render(request,'test.html',locals()
                  
# test.html模板文件
{{a|add:b}} # 在浏览器中显示3                  
2.length 统计变量的长度
{{a|length}}
函义:获取a的长度
注意:如果a是一个字典的化,返回的是字典的键值对个数


# view.py文件
def test(request):
    a = 123
    b = 22
    c = [1,2,3,4,5,6]
    d = {'user':'xichen','pwd':12456}
    return render(request,'test.html',locals()
                  
# test.html模板文件
{{a|length}}  # 返回3              
{{b|length}}  # 返回2
{{c|length}}  # 返回列表的长度5
{{d|length}}  # 返回字典的长度2
3.filesizeformat 将文件的大小转换为kb,mb的形式
{{file_size|filesizeformat}}
涵义::将值格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等)
    
# view.py文件
def test(request):
    a = 123
    b = 22
    c = [1,2,3,4,5,6]
    d = {'user':'xichen','pwd':12456}
    return render(request,'test.html',locals()
                  
# test.html模板文件
{{file_size|filesizeformat}}  # 11.5 GB             
4.truncatechars 获取字符的个数(后面加···)
5.truncatewords 获取单词的个数(后面加···)

# view.py文件
def test(request):
    content = '我是一只小鸟,自由自在的飞翔'
    word  = 'hello world are you name? whats your name'
    return render(request,'test.html',locals()
                  
# test.html模板文件
{{content|truncatechars:10}} # 我是一只小鸟,...  (···占3个位置)
{{word|truncatewords:5}}  # hello world are you name?··· (···不占位置,单词是按空格为依据)
6.slice 切片操作

lis = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
{{lis|slice:'0:3'}} # [1,2,3] 相当于列表的切片操作
{{lis|slice:'0:10:2'}} # [1, 3, 5, 7, 9] 步长为2的切片操作
{}
7.date :将日期按照指定的格式输出

time = datetime.now()
{{time|date:'Y-m-d'}} # 返回的是格式化时间2019-10-23
8.safe 将后端传给前端的html标签字符串,转义为html语言

html = '<h1>我是一级标题</h1>'
{{html|safe}} # 浏览器输出的就是正常的html语法,如果不转义的话,输出的就是遗传字符串

##注意:在这里我们可以通过前端的方市将html字符串形式的标签语言进行自动转义,那我们也可以在后端直接转义,然他传递到前端之前就转义好:用到make_safe()方法
先导入一个模块
from django.utils.safestring import mark_safe
html = '<h1>我是一级标题</h1>'
html = make_safe(html) # 这个时候html就已经转义了

四、模板语法之符号

4.1 变量用的模板语法符号

{{ 变量名 }} # 此处的变量名就是在后端传递过来的

4.2 逻辑相关的模板语法符号

{{% 逻辑符(if for with) %}} # 这样加百分号的是和逻辑相关的

# 另外这些逻辑标签要有对应的结束符
{{% endif%}}
{{% endfor %}}
{{% endwith %}}

1.常用逻辑标签for 标签

1、遍历每一个元素:
{% for user in user_list %}
	<p>{{ person.name }}</p> # 这里的内容是动态的
{% endfor %} 
 
2、可以利用{% for obj in list reversed %}反向循环

3、遍历一个字典:
{% for key,val in dic.items %}
	<p>{{ key }}:{{ val }}</p> 
{% endfor %} 
 
4、循环序号可以通过{{ forloop }}  
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0  当前循环的倒序索引值(从0开始)
forloop.first   当前循环是第一次循环则返回True,否则返回False 
forloop.last    当前循环是后一次循环则返回True,否则返回False 
forloop.parentloop   本层循环的外层循环 
 
5、for标签可以带有一个可选的{% empty %} 从句
在变量user_list为空或者没有被找到时,则执行empty子句 
{% for user in user_list %}     
	<p>{{ person.name }}</p> 
{% empty %} 
	<p>sorry,no user here</p> 
{% endfor %}

案例:

# view.py 文件
def test(request):
    user_list = ['xichen','chen','cecilia','chenyuxing']
    return render(request,'test3.html',locals())

# html模板文件
{% for user in user_list %}
	<p>{{user}}</p>
    {{ forloop }} <!--for 循环列表的序号-->
    
{% empty %}	<!--当user_list没有值的时候,会走empty下的子句-->
	<p>sorry,no user here!</p>
{% endfor %}

2. 常用标签之if 标签

1、注意:
{% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,在变量值为空、或者视 图没有为其传值的情况下均为False 
 
2、具体语法
{% if num > 100 or num < 0 %}  
	<p>无效</p>
    
{% elif num > 80 and num < 100 %}  
	<p>优秀</p> {% else %} 
    <p>凑活吧</p>
{% endif %} 
 
3、if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

注意:用if语句进行判断时,条件符号要与变量和条件必须空一个空格,否则报错

案例如下:

# views.py 文件
def test(request):
    num = 85
    return render(request,'test.html',locals())

# html 模板文件
{% if num > 90%}
    <p>优秀</p>
{% elif num > 80 %}  # 进入这个条件
    <p>中等</p>
{% else %}
    <p>及格</p>
{% endif %}

3. 常用标签之with标签

with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,在起别名后只需要使用别名即可,无需每次 都向数据库发送请求来重新获取变量的值
{% with user_list.1 as v %}  
	{{ v }} 
{% endwith %}

五、自定义过滤器和标签

自定义过滤器和标签的重要三步骤:

  1. 在当前应用下新建一个templatetags文件夹(文件夹的名字,必须是这个)
  2. 在新创建的templatetags文件夹下,新建一个my_tags.py文件(任意文件名)
  3. 在这个my_tags.py文件里写如下两行代码
from django.template import Library
register = Library()

5.1 自定义过滤器

自定义过滤器只能由两个参数:如果非要想传多个参数,那就按"[1,2,3,4,5]"容器类,按字符串传

from django.template import Library
register = Library()

@register.filter(name='my_safe') # 过滤器名为my_safe,如果这里不设置,那么过滤器名字为index
def index(a,b):
    return a*b


# 使用
{% load my_tags %} # 先加载过滤器.py文件
{{12|my_safe:10}} # 结果120 用过滤器的方法和内置的过滤器的方法一样

5.2 自定义标签

from django.template import Library
register = Library()

@register.simple_tag(name = 'mytag') # 标签名为mytag,如果这个地方不设置,那标签为login
def login(a,b,c):
    return a+b+c

# 使用
{%  load my_tags %}
{% mytag 1 2 3%} # 返回6

# 注意
自定义标签的使用,标签后和参数统一用空格隔开

5.3 总结

  • 自定义过滤器最多只能传两个参数,想传多个,那就放在容器类型里,并且用字符串的方式
  • 自定义标签可以传多个参数
  • 自定义的过滤器或者标签必须重启django项目方可生效
  • 自定义标签不能卸载 if 里面,自定义过滤器可以

六、模版的继承

顾名思义,这就像是儿子继承父亲的遗产

假设我有一个模板文件,这个模板文件中有个别部分是可以被别的模板文件直接拿去用的,如果别的模板文件引入到自己的模板文件里用了,这就叫继承

用到如下的模板语法:

{% extends = '模板名称' %} 搭配block标签

作用:在一个模板文件中,引入/重用另外一个模板文件的内容
# 父模板的使用

1.首先我们需要有一个父模板,它内部的所有框架,以及内容,只要是它自己规定了可以被继承的部分,其他的任何的子模版都可与继承
2.父模板如何标记自己的某一部分内容是可以被继承的
	在一段内容的头和尾用block来定义
    {% block 别名 %} #别名自己起 (可以被继承内容的开始)
    	'''
    	这里都是子模版可以继承的部分
    	'''
    {% endblock %}# 可以被继承内容的结束
# 子模版的使用

1.首先创建一个新的模板文件
2.ctrl+A ---> ctrl+x 清空这个模板文件的所有内容
3.写下面这句模板语法:
	{% extend  父模板的名字 %} # 这样打开子模版页面,发现和父模板的内容,框架,布局都一摸一样
    
4.只继承父模板并不是重点,重点是在子模版中可以重写父模板标志的可以被继承的部分
5.用如下语句重写父模板可以被子模版继承的部分
	{% block 父模板可以被继承部分的别名%}
    '''
    这里是子模版重写继承父模板的部分,自己有自己的布局,内容,样式
    '''
    {% endblock %}

七、模板的导入

在实际开发中,模板文件彼此之间可能会有大量冗余代码,为此有里导入模板,继承模板的这些专门的语法来解决这个问题

{ % include 'html'% }

# 这里是可以将一个特定的部分布局,写入一个专门的html文件里,然后只要需要用到这个布局的模板都只要导入这个布局的html页面就可以了

总结与注意:

#1、标签extends必须放在首行,base.html中block可继承的部分越多可定制性越强 
 
#2、include仅仅只是完全引用其他模板文件,而extends却可以搭配block在引用的基础上进行扩写 
 
#3、变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖 
 
#4、为了提升可读性,我们可以给标签{% endblock %} 起一个名字 。例如:     {% block content %}     ...     {% endblock content %}   #5、在一个模版中不能出现重名的block标签。

八、静态文件配置

我们在编写模板文件时,需要大量引用css、js、图片等静态文件,如果我们将这 些文件在服务端存放的路径都固定写死那么将非常不利于后期的扩展,我们可以 这么做

  1. 在Django项目的根目录下,新建一个static文件夹,并且内部包含一些CSS,js,jpg,等固定文件

  2. 与项目名同名的文件夹下的settings.py文件中

    STATIC_URL = '/static/' # 找到这一行,然后新增下述代码
    STATICFILES_DIRS = [     
        os.path.join(BASE_DIR, 'statics'),# 获取静态文件在服务端的绝对路径 
    ]
    #STATIC_URL = '/static/'就是为静态文件的绝对路径起了一个别名,以后我们只需要用路径/static/即可 
    
posted @ 2019-10-24 16:49  Cecilia陈  阅读(136)  评论(0编辑  收藏  举报