Django模板层的知识包括标签、过滤器、自定义标签、自定义过滤器以及inclusion_tag,最重要的是模板的继承和导入。css
首先模板层最重要的是模板语法,以前咱们提过涉及到变量用模板语法{{ }},涉及到逻辑用模板语法{% %},这里再追加几点。过滤器在模板语法{{ }}中写,并且只能传两个参数;标签在模板语法{%%}中写,并且能传多个参数(参数间用空格隔开)。模板的继承与导入也是在模板语法{%%}中写。html
接下来再回顾一下后端朝前端页面传递数据的两种方式:前端
# 第一种 return render(request, 'index.html', {'nums': nums}) # 第二种 return render(request, 'index.html', locals())
该两种方法有利有弊,不过咱们偏心locals()。python
后端除了能向前端提交python的基本数据类型:int、float、str、list、dict、tuple、set数据外,还能提交函数与类的对象。当咱们传递函数名给前端时,会自动调用该函数拿到函数return的结果,可是不支持传参,因此只能传递无参函数名。当传递类的对象obj给前端时,至关于print(obj),前端拿到的是该obj的内存地址,由于print(obj)走的是类的__str__()方法。因此传递类的对象时,咱们能够重写__str__()让前端拿到想要的内容。jquery
前端想要获取后端传递过来的容器类型中的元素时,统一使用句点符(.):django
<!--假设前端拿到的数据是 L = [1, 2, 3] D = {'age': 18}--> {{ L }} <!--[1, 2, 3]--> {{ L.1 }} <!-- 2 索引也是从0开始--> {{ D }} <!--{'age': 18}--> {{ L.age }} <!-- 18 -->
前端能够调用python自带的内置方法,不过只能调用不须要传参的,好比字典dic的dic.keys(),dic.values(),dic.items()等,注意:在前端调用方法不须要加(),直接dic.keys便可。bootstrap
模板语法的注释不会展现到前端(用谷歌浏览器的检查也看不到),只能在后端看到,原生的HTML注释先后端均可以看到。后端
过滤器在模板语法{{ }}中书写,实际上过滤器内部走的是后端的语法,过滤器最多支持传两个参数(会把|左边的参数当作过滤器的第一个参数传进去),不过能够把参数改为容器类型,而后在内部动手脚处理参数中的数据,间接实现传递多参数,这须要咱们自定义过滤器来实现。浏览器
过滤器基本语法:{{ 参数1|过滤器名字:参数2 }} 有些过滤器没有参数2。安全
若是file_size是204800,执行该过滤器后是 200.0KB
不须要同后端同样加%('%Y-%m-%d'),若是ctime是2019-06-11 16:56:38.903314,执行完该过滤器后是2019-06-11。
若是s='hello world',执行完该过滤器后是‘hlow’,slice后面的参数同python字符串切片参数同样,开头:结尾:步长,其中步长默认为1,切片顾头不顾尾。
若是s='hello world',执行完该过滤器后是‘hello w...’,超出长度的部分会用...代替,当咱们参数为10时,实际上截取的字符串长度为7,由于...占3位。
若是s='he llo wor ld',执行完该过滤器后是:‘he llo ...’,截取至前两个空格,以后的内容用...表示。
若是n1=2, n2=4,那么结果为6。若是n1='hello', n2='world',那么结果为'helloworld'。
重点:
当咱们后端向前端提交的字符串含有标签时,好比'<h1>this is title</h1>',为了防止脚本攻击(好比<script>while(1){alert('come on')}</script>),前端以后把你当成普通的字符串。当咱们想要让前端帮咱们执行提交的字符串中的标签内容时,有两种方式。
from django.utils.safestring import mark_safe def index(request): html = reverse('index') s = '<h1>this is title</h1>' s = mark_safe(s) return render(request, 'index.html', locals()) # 前端直接{{ s }}便可
标签在模板语法{%%}中书写,{%%}涉及到逻辑,标签通常是for循环,if判断以及它们的嵌套使用,除此以外还有empty标签。
for循环中可使用forloop来给咱们提供一些信息:
<!--l = [1, 2, 3, 4, 5]--> {% for foo in l %} <p>{{ foo }}</p> <p>{{ forloop }}</p> {% endfor %}
{% if flag %} <p>flag不为空</p> {% else %} <p>flag是空</p> {% endif %}
{% for foo in s %} {% if forloop.first %} <p>这是第一次</p> {% elif forloop.last %} <p>这是最后一次</p> {% else %} <p>keep up</p> {% endif %} {% endfor %}
{% for foo in l %} {% if forloop.first %} <p>这是个人第一次</p> {% elif forloop.last %} <p>这是最后一次了啊</p> {% else %} <p>嗨起来!!!</p> {% endif %} {% empty %} <p>你给个人容器类型是个空啊,无法for循环</p> {% endfor %}
当后端传来的数据中,咱们想要的数据须要句点符点不少次才能拿到且后面还须要用到该数据时,咱们能够选择给该数据取别名。
要自定义过滤器与标签,必须先作三件事:
from django import template register = template.Library()
再次强调,必定要按照以上步骤进行,文件夹必定要叫templatetags!!!
from django import template register = template.Library() # 自定义过滤器 @register.filter(name='my_add') # name是HTML页面中调用该过滤器用的名字 def my_add(a, b): return a+b
from django import template register = template.Library() @register.simple_tag(name='my_tag') def my_tag(a, b, c): return a + b + c
from django import template register = template.Library() @register.inclusion_tag('login.html', name='login') def login(n): l = ['第%s项' % i for i in range(n)] return {'l': l}
<!--login.html--> <ur> {% for foo in l %} <li>{{ foo }}</li> {% endfor %} </ur>
在该例子中,咱们在前端调用inclusion_tag时:
{% load my_tags %}
{% login 5 %}
首先会将参数5传给login函数,函数执行完后的结果提交至login.html,而后将login.html的页面显示在调用该inclusion_tag的地方。
inclusion_tag会将渲染过的login.html界面返回至调用它的位置,正是由于这种机制,因此它所渲染那个html页面中能够不须要head和body等各类标签,你须要返回什么就在里面写什么。
想要使用自定义的过滤器、标签和inclusion_tag,必需要先在html界面中加载该模块
<!--加载my_tags.py模块--> {% load my_tags %} {{ n1|my_add:n2 }} <!--调用自定义过滤器--> {% my_tag n1 n2 n3 %} <!--调用自定义标签--> {% login 5 %} <!--调用自定义inclusion_tag-->
1.1 首先须要被继承的模板中划分多个区域:
{% block 给区域起的名字 %}
{% endblock %}
1.2 一般状况下一个模板中至少有三块区域:
{% block css %}
页面css代码块
{% endblock %}
{% block js %}
页面js代码块
{% endblock %}
{% block content %}
页面主体内容
{% endblock %}
1.3 子模板继承模板,首先要先继承模板全部的内容:
{% extends 'home.html' %}
1.4 根据被block快的名字修改指定区域的内容
{% block content %} <h1>登陆页面</h1> <form action=""> <p>username:<input type="text" class="form-control"></p> <p>password:<input type="text" class="form-control"></p> <input type="submit" class="btn btn-success"> </form> {% endblock %}
1.5 可使用{{ block.super }}使用父模板的该block的内容(使用该方法是没有提示,要手打)
{% block content %}
{{ block.super }}
{% endblock %}
注意:原模板中的block区域越多越好,由于越多表明能够修改的细节不少,扩展性就越强。继承后,子模板只能修改block区域中的内容。
模板导入同自定义标签inclusion_tag有点像,都是将一个HTML页面显示到调用它们的地方,并且他们的HTML页面都是要啥就写啥就好了,不须要body、head等标签。不过inclusion_tag是动态的,能够传递参数,而模板导入是静态的。
模块导入{% include '想导入的html文件名' %}:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>login2</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <!--导入模板index2.html--> {% include 'index2.html' %} </body> </html>
<h1>我是这条gai最靓的仔</h1> <form action=""> <p><input type="text"></p> <p><input type="text"></p> <input type="submit"> </form>
当咱们为了让路由名字改变时咱们不须要修改HTML页面和视图函数中的内容,咱们引入了反向解析。同理,为了防止settins.py文件夹中static文件夹的接口前缀改变而咱们不须要html页面中head中script和link的接口前缀(须要修改的前提是他们导入的是static文件夹中的东西),咱们引入了静态文件配置。
{% load static %} <link rel='stylesheet' href="{% static 'css/mycss.css'%}"> # 第一种方式 <link rel='stylesheet' href="{% get_static_prefix %}css/mycss.css"> # 第二种方式