在django中,模板引擎(DTL)是一种可以让开发者将服务端数据填充到html页面中的完成渲染的技术
模板引擎的原理分为以下三步:
-
在项目配置文件中指定保存模板文件的的模板目录,一般设置在项目根目录或者子应用目录下
-
在模板目录下创建对应的模板文件
-
在视图函数中通过render函数绑定模板文件和需要渲染的数据
1.模板目录
在简单的项目中,我们通常在项目的根目录下创建名为templates的文件夹,并在配置文件中设置模板目录
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / "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', ], }, }, ]
如果是多app的情况下,我们不仅要设置主模板目录,还要在每个app下创建对应的templates,包含该子app所需要的模板文件
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / "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', ], }, }, ]
提示:在使用模板的时候,django会到主模板目录下寻找,找不到会按照顺序到已注册的项目下的模板目录中寻找
简单案例
路由
from django.contrib import admin from django.urls import path, include from apps.app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.index) ]
视图
def index(request): return render(request, 'app01/index.html')
模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> </body> </html>
2.render函数的本质
render函数的本质就是将模板文件中的所有变量替换成后端数据,生成一个html页面,也就是纯文本,响应给客户端
模板文件 & html页面的区别
模板文件是含有特殊语法的html文件,这个语法可以被django的DTL编译,将数据传进,实现动态话,渲染之后的模板文件也就是一个普通的html文件了
开发中我们常将普通的html称之为静态文件,将模板文件称之为动态文件
视图函数
def index(request): name = 'kunmzhao' return render(request, 'app01/index.html', {'name':name}) # 将数据传递给模板文件
模板文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ name }}</p> #含有模板语法 </body> </html>
渲染之后的html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>kunmzhao</p> # 渲染之后 </body> </html>
3.模板语法
3.1 句点符
变量渲染可以将对象原封不动的渲染在页面
def index(request): # 字符串 name = 'kunmzhao' # 数字 age = 18 # 列表 course = ['语文', '数学', '英语'] # 元组 hobby = ('篮球', '足球') # 字典 parents = {'father': 'mayun', 'mother': "dongmingzhu"} # 集合 teachers = {'alex', 'victor'} return render(request, 'app01/index.html', { 'name': name, 'age': age, 'course': course, 'hobby': hobby, 'parents': parents, 'teachers': teachers, }
句点符就可以访问对象中的属性
from django.shortcuts import render, HttpResponse # Create your views here. class Animal(object): def __init__(self, name, age): self.name = name self.age = age def index(request): # 字符串 name = 'kunmzhao' # 数字 age = 18 # 列表 course = ['语文', '数学', '英语'] # 字典 parents = {'father': 'mayun', 'mother': "dongmingzhu"} # 对象 dog = Animal('rubby', 3) return render(request, 'app01/index.html', { 'name': name, 'age': age, 'course': course, 'parents': parents, 'dog': dog } )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ name }}</p> <p>{{ age }}</p> <p>{{ course.0 }}</p> # 访问列表第几个元素 <p>{{ course.1 }}</p> <p>{{ course.2 }}</p> <p>{{ parents.father}}</p> # 访问字典中键对应的值 <p>{{ parents.mother }}</p> <p>{{ dog.name }}</p> # 访问对象发的属性 <p>{{ dog.age }}</p> </body> </html>
3.2 过滤器
3.2.1 内置过滤器
内置过滤器最多有一个参数
语法:
{{obj|过滤器名称:过滤器参数}}
用法 | 代码 | |
---|---|---|
last | 获取列表/元组的最后一个成员 | {{liast | last}} |
first | 获取列表/元组的第一个成员 | {{list|first}} |
length | 获取数据的长度 | {{list | length}} |
defualt | 当变量没有值的情况下, 系统输出默认值, | {{str|default="默认值"}} |
safe | 让系统不要对内容中的html代码进行实体转义 | {{htmlcontent| safe}} |
upper | 字母转换成大写 | {{str | upper}} |
lower | 字母转换成小写 | {{str | lower}} |
title | 每个单词首字母转换成大写 | {{str | title}} |
date | 日期时间格式转换 | {{ value| date:"D d M Y" }} |
cut | 从内容中截取掉同样字符的内容 | {{content | cut:"hello"}} |
list | 把内容转换成列表格式 | {{content | list}} |
add | 加法 | {{num| add}} |
filesizeformat | 把文件大小的数值转换成单位表示 | {{filesize | filesizeformat}} |
join |
按指定字符拼接内容 | {{list| join("-")}} |
random |
随机提取某个成员 | {list | random}} |
slice |
按切片提取成员 | {{list | slice:":-2"}} |
truncatechars |
按字符长度截取内容 | {{content | truncatechars:30}} |
truncatewords |
按单词长度截取内容 |
def index(request): name = 'kunmzhao' hobby = ['篮球', '足球'] return render(request, 'app01/index.html', { 'name': name, 'hobby': hobby, } )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ name|upper }}</p> <p>{{ hobby|first }}</p> <p>{{ hobby|last }}</p> </body> </html>
3.2.2 自定义过滤器
内置的过滤器可能没办法满足开发需求,django中支持使用自定义的过滤器
-
-
from django import template register = template.Library() # 自定义过滤器 @register.filter() def mobile(content): return content[:3] + "*****" + content[-3:]
- 在模板中load过滤器并使用
{% load my_filter %} # 导入自定义的过滤器 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ phone|mobile }}</p> # 使用过滤器 </body> </html>
3.3 标签渲染
3.3.1 if
语法:
{% if 条件 %}
{%endif %}
视图
def index(request): score = 80 return render(request, 'app01/index.html', { 'score': score, } )
模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% if score > 90 %} <p>成绩优秀啊</p> {% elif score > 80 %} <p>成绩良好</p> {% else %} <p>成绩一般</p> {% endif %} </body> </html>
3.3.2 for
语法
{% for i in iter %}
{%endfor %}
for标签中常用的方法
forloop.counter : 从1开始每次循环自增1
forloop.counter0 : 从0开始每次循环自增1
forloop.first : 是否是第一次循环
forloop.last : 是否是最后一循环
视图
def index(request): hobby = ['篮球', '足球', '乒乓球'] return render(request, 'app01/index.html', { 'hobby': hobby, } )
模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% for foo in hobby %} <p><span>{{ forloop.counter }}</span>{{ foo }}</p> {% endfor %} </body>
4.模板自定义
- filter
见自定义过滤器 参数:1-2个
- Simple_tag
返回文本 参数:无限制
- Inclusion_tag
返回html片段 参数无限制
定义
# encoding:utf-8 # author:kunmzhao # email:1102669474@qq.com from django import template register = template.Library() # 自定义过滤器 @register.filter() def mobile(content): return content[:3] + "*****" + content[-3:] # 自定义simple_tag @register.simple_tag() def mytag(a1, a2): return a1 + a2 # 自定义inclusion_tag @register.inclusion_tag("app01/menu.html") def my_inclusion(): return {'name': 'kunmzhao', 'age': 18}
模板
{% load my_filter %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ phone |mobile }}</p> # 使用自定义的过滤器 <p>{% mytag 100 200 %}</p> # 使用自定义的tag函数 <p>{% my_inclusion %}</p> # 使用自定义的inclusion_tag </body> </html>
menu.html
<p> <span>name={{ name }}</span> <span>age={{ age }}</span> </p>
5.模板继承和导入
{% include "模板文件名"%} # 模板嵌入
{% extends "base.html" %} # 模板继承
5.1 继承
语法
{%entends 模板文件%} # 继承指定的模板文件
{% block 名称 %} # 填充模板中的某一个block
{% endblock %}
视图
def index(request): return render(request, 'app01/header.html')
模板header.html
{% extends 'app01/index.html' %} {% block body%} <div>不畏浮云遮望眼,只缘身在最高层</div> {% endblock %}
模板index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% block css %} {# css样式 #} {% endblock %} </head> <body> {% block body %} {# 内容填充 #} {% endblock %} </body> </html>
5.2 导入
{% include 片段文件名%}
视图
def index(request): return render(request, 'app01/header.html', {'name': 'kunmzhao', 'age': 18})
模板menu.html
<p> <span>name={{ name }}</span> <span>age={{ age }}</span> </p>
模板header.html
{% extends 'app01/index.html' %} {% block body %} <div>不畏浮云遮望眼,只缘身在最高层</div> {% include 'app01/menu.html' %} # 导入片段 {% endblock %}
6.静态文件
我们通常会将前端的css, js等代码发在app对应的static目录下,我们在模板中导入css或者js等代码的时候,引入{ %load static %}
跟templates类似,在多app下,我们通常会在每个app下创建一个static的文件夹,再创建对应app名字的文件件,将该app下使用的静态文件放在该目录