Django之模板层
模板层
常用语法
只需要两种特殊符号:{{}}
和{% %}
- 变量相关的用
{{}}
- 逻辑相关的用
{% %}
注释
注释是代码之母:
-
单行注释:
{# #}
-
多行注释:
1 {% comment %} 2 <注释内容> 3 {% endcomment %
注:模板语法的注释前端无法查看。
模板语法之传值
python基本数据类型传值
# 视图层
from django.shortcuts import render def index_func(request): i = 666 f = 11.11 s = 'hello world' l = [111, 222, 333, 444] d = {'username': 'alex', 'password': 123, 'hobby': ['read', 'study', 'run']} t = (111, 222, 333) se = {111, 222, 333} b = True b1 = False # 传值方式1:指名道姓,利用字典挨个传值 return render(request, 'indexPage.html', {'i': i, 'f': f, 's': s}) # 传值方式2:简单粗暴 locals()将当前名称空间中所有的变量名全部传递给页面 return render(request, 'indexPage.html', locals())
# 模板层
<body> <p>{{ i }}</p> <p>{{ f }}</p> <p>{{ s }}</p> <p>{{ l }}</p> <p>{{ d }}</p> <p>{{ t }}</p> <p>{{ se }}</p> <p>{{ b }}</p> <p>{{ b1 }}</p> </body>
效果展示:
传值方式的优缺点:
- 传值方式一:传值精确,不会造成资源浪费
- 传值方式二:传值粗糙,可能会造成一定的资源浪费
模板语法传值特性
点(.)在模板语言中有特殊的含义。
- django模板语法取值只能采用 句点符
(.)
也就是点 - 可以根据索引以及键取值,索引、键都可以无限制的点点点……
# 视图层
def index_func(request): d = {'username': 'alex', 'password': 123, 'hobby': ['read', 'study', 'run']} return render(request, 'indexPage.html', locals())
# 模板层
<p>{{ d.hobby.2 }}</p> {#获取字典里hobby对应的索引为2的数据#}
效果展示:
当模版系统遇到点("."),它将以这样的顺序查询:
- 字典查询
- 属性或方法查询
- 数字索引查询
文件对象传值
# 视图层
from django.shortcuts import render def index_func(request): f_obj = open(r'C:\Users\独孤傲\Desktop\数学网站.docx','rb') return render(request, 'indexPage.html', locals())
# 模板层
<p>{{ f_obj }}</p>
<p>{{ f_obj.read }}</p> {#文件对象也可以展示并调用方法#}
效果展示:
函数传值特性
# 视图层
from django.shortcuts import render def index_func(request): def func1(): print('快过年了') return '要加油啊' return render(request, 'indexPage.html', locals())
# 模板层
<p>{{ func1 }}</p>
前端页面展示结果:
pycharm执行结果:
说明:函数名会自动加括号执行并将返回值展示到页面上(不支持额外传参)
类的传值特性
# 视图层
def index_func(request): class MyClass(object): def get_obj(self): return '绑定给对象的方法' @classmethod def get_cls(cls): return '绑定给类的方法' @staticmethod def get_static(): return '静态方法' obj = MyClass() return render(request,'indexPage.html',locals())
# 模板层
<p>{{ MyClass }}</p> <p>{{ obj }}</p>
展示结果:
从上面的结果发现:
- 类和类产生的对象展示的结果是一样的,都是一个对象,说明类名也会自动加括号调用,对象则不会。
- 对象还可以继续通过点的方式调用方法。
模板语法之过滤器(内置函数)
在Django
的模板语言中,通过使用 过滤器 来改变变量的显示,大约有60种过滤器,这里只介绍常用过滤器。
模板语法
{{ 变量名 | 过滤器:可选参数 }} eg:{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。lower在这里的作用是将文本全都变成小写。
# 视图层:
def index(request): # python基本数据类型 i = 666 f = 11.11 s = 'hello world 干饭人 干饭魂 我们都是打工人!' l = [111, 222, 333, 444] d = {'username': 'alex', 'password': 123, 'hobby': ['read', 'study', 'run']} t = (111, 222, 333) se = {111, 222, 333} w = 'aa bb cc dd ee ff' b = True b1 = False file_size= 2384024 return render(request, 'index.html', locals())
常见过滤器
# 模板层:
<body> {# 类似于python的内置方法#} <p>过滤器:将竖杆左侧的数据当做第一个参数</p> <p>统计长度:{{ s|length }}</p> <!-- add数字相加,字符拼接--> <p>加法运算:{{ i|add:100000000000 }}</p> <p>字符串拼接:{{ s|add:'heiheihei' }}</p> <p>拼接:{{ s|join:'@' }}</p> <p>切片:{{ l|slice:'0:5:2' }}</p> <p>日期格式:{{ ctime|date:'Y年-m月-d日 H时:i分:s秒' }}</p> <!-- 如果第一个参数的布尔值是true则显示左边的值,否则显示default后的值--> <p>默认值:{{ b|default:'哈哈' }}</p> <p>默认值:{{ b1|default:'哈哈' }}</p> <!-- 截取内容包含三个点,并且算在字符个数之内--> <p>文件大小:{{ file_size|filesizeformat }}</p> <p>截取文本(三个点也算):{{ s|truncatechars:6 }}</p> <!-- 截取内容包含三个点,但不算在单词个数之内,单词识别是以空格来区分的--> <p>截取文本(三个点不算)空格:{{ s|truncatewords:3 }}</p> </body>
展示结果:
注意事项:
- 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
- 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
- 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:’, ’ }}
- '|'左右没有空格没有空格没有空格
转义(safe过滤器)
Django
会自动对 views.py
传到HTML文件中的标签语法进行转义,令其语义失效。加 safe 过滤器是告诉 Django
该数据是安全的,不必对其进行转义,可以让该数据语义生效。
# 视图层:
from django.shortcuts import render def index_func(request): h1 = '<h1>哈哈哈哈哈哈</h1>' views_str = "<a href='https://www.baidu.com'>点我进入百度</a>" return render(request, 'indexPage.html', locals())
# 模板层:
<p>{{ h1 }}</p> <p>{{ views_str }}</p>
展示结果:
加 safe 过滤器之后:
<p>{{ h1|safe }}</p> <p>{{ views_str|safe }}</p>
展示结果:
总结:前端代码不一定非要在前端页面写,可以在后端写好后传递给前端页面使用,这样的话,你就可以利用到后端更加多的逻辑语法。
模板中的for循环
{% for 循环变量 in 循环对象 %} 循环执行的语句 {%empty%} 循环对象本身是空的时候,执行的代码 {% endfor%} {# 结束循环 #}
模板中的判断语句
{{% if 条件1(可以自己写也可以用传递过来的数据) %} <p>满足条件1执行的语句</p> {% elif 条件2(可以自己写也可以用传递过来的数据) %} <p>满足条件2执行的语句</p> {% else %} <p>以上条件都不满足时执行的语句</p> {% endif %}
示例
# 视图层
from django.shortcuts import render def index_func(request): l = [111,222,333,444,555,666] return render(request, 'indexPage.html', locals())
# 模板层
{% for k in l %} {% if forloop.first %} <p>这是我的第一次循环{{ k }}</p> {% elif forloop.last %} <p>这是我的最后一次循环{{ k }}</p> {% else %} <p>这是中间循环{{ k }}</p> {% endif %} {% empty %} <p>你给我传的数据是空的无法循环取值(空字符串、空列表、空字典)</p> {% endfor %}
展示结果:
补充:
{% for %}标签内部模板变量forloop
在{% for %}循环内部,可以访问一个名为forloop的模板变量。这个变量有若干属性,通过它们可以获知循环进程的一些信息。
forloop.counter forloop.counter 的值是一个整数,表示循环的次数。这个属性的值从 1 开始,因此第一次循环时,forloop.counter 等于 1 。 forloop.first forloop.first 是个布尔值,第一次循环时为 True 。
起别名(了解)
复杂数据获取之后需要反复使用可以起别名
d = {'name':'alex', 'age':18, 'hobby':['read','study',{'else':'sleep'}]} {% with d.hobby.2.else as else_hobby %} {{ hobby }} {{ else_hobby }} {% endwith %}
# 别名只可以在with里面用,with外面就失效了
类似于python里面的自定义函数
1. 前期准备工作:
-
在应用下创建一个名字必须叫"templatetags"文件夹
-
在上述文件夹内创建一个任意名称的
py
文件 -
在该py文件内固定先书写以下两句话
from django import template register = template.Library()
2.自定义过滤器
- 自定义过滤器最多只能有两个形参
# 在模板层导入自定义的过滤器时使用的是这里指定的名字 @register.filter(name='myfilter') def sums(a, b): # 函数名随便起什么 return a + b # 返回两个参数的和 #模板层 {% load mytags %} # 导入tags文件 <p>{{ i|myfilter:100 }}</p> # 使用myfilter过滤器
3.自定义标签simple_tag
- 自定义标签可以有多个参数
# 自定义标签(参数没有限制)
@register.simple_tag(name='my_tag') # 在模板层导入自定义的标签时使用的是这里指定的名字 def my_join(a,b,c,d): # 函数名任意 return f'{a}/{b}/{c}/{d}' # 返回参数拼接后的结果 # 模板层: {% load mytags %} {% my_tag 'aaa' 'bbb' 'ccc' 'ddd' %} # 参数之间用空格隔开
4.自定义inclusion_tag
- 当一些数据在前端的很多页面上需要反复使用,并且可以在前端通过传不同的参数渲染不同的结果,那么就可以制作一个inclusion_tag。
- inclusion_tag的使用可以帮我们减少很多前端和后端重复的代码
inclusion_tag 的内部原理:
- 前端某个HTML页面调用inclusion_tag
- 触发了py文件中一个函数的执行,通过函数的逻辑处理并产生一些数据
- 产生的数据通过模板语法传递给一个局部HTML页面进行渲染
- 渲染完毕后又返回调用inclusion_tag的位置进行展示
# 自定义inclusion_tag的py文件
@register.inclusion_tag('menu.html',name='mymenu') # 第一个参数是需要渲染的HTML页面 def func(n): html =[] for i in range(n): html.append('<li>第%s页</li>'%i) return locals() # 将数据传给局部HTML页面
# 局部页面(menu.html)
<ul> {% for liStr in html %} # 接收函数传递过来的数据 {{ liStr|safe }} {% endfor %} </ul>
# 真正要使用数据的前端页面
{% load mytags %} # 导入编写inclusion_tag的页面 {% mymenu 10 %} # 导入局部页面并传参
模板的继承与导入
模板的继承
- 模板的继承首先需要选择一个母板页面, 在该页面里面使用 block 划定可以被更改的区域
# 母板页面 'home.html' 文件
{% block [区域名称] %} # 区域名称自己取
...... # 这部分为划分出来的区域,可以在子板中进行修改
{% endblock %}
- 想要继承的页面可以使用 extends 来继承某一个页面
# 子版
{% extends 'home.html' %}
{% block [区域名称] %} # 与母版中划分出来的区域名称一致
...... # 自己可以另外设计样式
{% endblock %}
子版继承了母板, 那么子版的整体格式与母板一样, 被 block 划分了的区域可以自己随意更改
母板的三个区域
- 母板在划分区域的时候一般有三个区域
{% block css %} # css区域 {% endblock %} {% block content %} # HTML区域 {% endblock %} {% block js %} # js区域 {% endblock %}
总结:
- 在母板中可以定义块,子类可以重写该部分内容。
- 模板继承也是为了重用html页面内容,并且具有独立的css、js等,减少代码的冗余,同时增加扩展性
模板的导入
- 将某个html的部分提前写好,之后很多html页面想使用就直接导入,类似于后端的模块。
# 被导入的myform.html(是一个局部页面)
{% include 'myform.html' %} # 把'myform.html'的页面导入到你想使用的页面
与inclusion_tag很像,但inclusion_tag的参数可以动态获取,这个数据是写死的。