django的模板
模板
在工作中为了更好的展示数据给用户,所以都会使用html+css+js实现网页排版效果,但是很多开发人员并不能做到既擅长服务端开发又擅长前端开发的,当然,即便有,那这个开发人员的工资也不会低,而且同等条件下,1个人干活是怎么也比不过2个人的。所以,怎么让服务端的数据更好的展示到客户端,这就成为问题了。
模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术。它实现了把前端代码和服务端代码分离的作用,让项目中的业务逻辑代码和数据表现代码分离,让前端开发者和服务端开发者可以更好的完成协同开发。
Django框架中内置了web开发领域非常出名的一个DjangoTemplate模板引擎(DTL)。
DTL官方文档: https://docs.djangoproject.com/zh-hans/3.2/topics/templates/
-
在项目配置文件中指定保存模板文件的模板目录。
一般模板目录都是设置在项目根目录或者主应用目录下。
-
在视图中基于django提供的渲染函数绑定模板文件和需要展示的数据变量
-
在模板目录下创建对应的模板文件,并根据模板引擎内置的模板语法,填写输出视图传递过来的数据。
# 模板引擎配置 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', ], }, }, ]
settings.py,中注册子应用的代码:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'tem', # 开发者创建的子应用,这填写就是子应用的导包路径 ]
配置路由文件,总路由和子路由;
from django.shortcuts import render def index(request): # 要显示到客户端的数据 name = "hello DTL!" # return render(request, "模板文件路径",context={字典格式:要在客户端中展示的数据}) return render(request, "index.html",context={"name":name})
templates中接受视图传过来的参数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>来自模板的内容</h1> <p>输出变量name的值:{{ name }}</p> </body> </html>
探究
from django.shortcuts import render from django.template.loader import get_template from django.http.response import HttpResponse def index(request): name = "hello world!" # 1. 初始化模板,读取模板内容,实例化模板对象 # get_template会从项目配置中找到模板目录,我们需要填写的参数就是补全模板文件的路径 template = get_template("index.html") # 2. 识别context内容, 和模板内容里面的标记[标签]替换,针对复杂的内容,进行正则的替换 context = {"name": name} content = template.render(context, request) # render中完成了变量替换成变量值的过程,这个过程使用了正则。 print(content) # 3. 通过response响应对象,把替换了数据的模板内容返回给客户端 return HttpResponse(content) # 上面代码的简写,直接使用 django.shortcuts.render # return render(request, "index.html",context={"name":name}) # return render(request,"index3.html", locals()) # data = {} # data["name"] = "xiaoming" # data["message"] = "你好!" # return render(request,"index3.html", data)
相关的拓展知识
# 1. DTL模板文件与普通html文件的区别在哪里? DTL模板文件是一种带有特殊语法的HTML文件,这个HTML文件可以被Django编译,可以传递参数进去,实现数据动态化。在编译完成后,生成一个普通的HTML文件,然后发送给客户端。 # 2. 开发中,我们一般把开发中的文件分2种,分别是静态文件和动态文件。 静态文件,数据保存在当前文件,不需要经过任何处理就可以展示出去。 普通html文件,图片,视频,音频等这一类文件叫静态文件。 动态文件,数据并不在当前文件,而是要经过服务端或其他程序进行编译转换才可以展示出去。 编译转换的过程往往就是使用正则或其他技术把文件内部具有特殊格式的变量转换成真实数据。 动态文件,一般数据会保存在第三方存储设备,如数据库中。 django的视图,模板文件,就属于动态文件。 # 3. 除了render,django还提供了一个render_to_string函数 ,可以将函数结果提供给 HttpResponse直接返回给客户端。 # 代码参考如下: from django.http.response import HttpResponse from django.template.loader import render_to_string def index(request): # 要显示到客户端的数据 name = "hello DTL!" tpl_content = render_to_string('index.html', {"name":name}) return HttpResponse(tpl_content)
"""变量""" {{ 变量 }} """注释""" {# 单行注释 #} {% comment %} 多行注释 {% endcomment %} """标签""" {% 标签名 %} {% 开始标签 %} {% 结束标签 %} """过滤器""" # 本质就是函数[可以是python函数,也可以是开发者自定义函数] # 单个无参数过滤器,变量默认作为过滤器的第1个参数,过滤器中return的内容作为结果被输出 {{ 变量 | 过滤器 }} # 单个有参数过滤器,django的过滤器只能额外接收1个参数。 {{ 变量 | 过滤器:参数2}} # 多个无参数过滤器,每个 | (竖杠) 左边的内容作为右边过滤器的默认第1个参数 {{ 变量 | 过滤器1 | 过滤器2 | 过滤器3 | ..... }} # 多个有参数过滤器,每个过滤器的参数1是 竖杠作为结果。最后一个过滤器返回的结果被输出 {{ 变量 | 过滤器1:参数2 | 过滤器2:参数2 | .... }}
变量,视图的演示
def index5(request): name = "root" age = 13 sex = True lve = ["swimming", "shopping", "coding", "game"] bookinfo = {"id": 1, "price": 9.90, "name": "python3天入门到挣扎", } book_list = [ {"id": 10, "price": 9.90, "name": "python3天入门到挣扎", }, {"id": 11, "price": 19.90, "name": "python7天入门到垂死挣扎", }, ]
book_list1 = [
{"id": 11, "name": "python基础入门", "price": 130.00},
{"id": 17, "name": "Go基础入门", "price": 230.00},
{"id": 23, "name": "PHP基础入门", "price": 330.00},
{"id": 44, "name": "Java基础入门", "price": 730.00},
{"id": 51, "name": "C++基础入门", "price": 300.00},
{"id": 56, "name": "C#基础入门", "price": 100.00},
{"id": 57, "name": "前段基础入门", "price": 380.00},
]
return render(request, 'index5.html', locals()) //locals()函数可以将所有的变量一起返回到template当中
模板的代码演示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>name={{ name }}</p> <p>{{ age }}</p> <p>{{ sex }}</p> <p>列表成员</p> <p>{{ lve }}</p> <p>{{ lve.0 }}</p> <p>{{ lve | last }}</p> <p>字典成员</p> <p>id={{ bookinfo.id }}</p> <p>price={{ bookinfo.price }}</p> <p>name={{ bookinfo.name }}</p> <p>复杂列表</p> <p>{{ book_list.0.name }}</p> <p>{{ book_list.1.name }}</p> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {# 来自django模板引擎的注释~~~~ #} {% comment %} 多行注释,comment中的所有内容全部都不会被显示出去 {% endcomment %} {# {% if age < 18 %}#} {# <p>你还没成年,不能访问我的网站!</p>#} {# {% endif %}#} {##} {# {% if name == "root" %}#} {# <p>超级用户,欢迎回家!</p>#} {# {% else %}#} {# <p>{{ name }},你好,欢迎来到xx网站!</p>#} {# {% endif %}#} {% if user_lve == lve.0 %} <p>那么巧,你喜欢游泳,海里也能见到你~</p> {% elif user_lve == lve.1 %} <p>那么巧,你也来收快递呀?~</p> {% elif user_lve == lve.2 %} <p>那么巧,你也在老男孩?</p> {% else %} <p>看来我们没有缘分~</p> {% endif %} </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table width="800" align="center" border="1"> <tr> <td>序号</td> <td>id</td> <td>标题</td> <td>价格</td> </tr> {# 多行编辑,alt+鼠标键,alt不要松开,左键点击要编辑的每一行 #} {# {% for book in book_list1 %}#} {# <tr>#} {# <td>{{ book.id }}</td>#} {# <td>{{ book.name }}</td>#} {# <td>{{ book.price }}</td>#} {# </tr>#} {# {% endfor %}#} {# 建议不要直接使用for循环一维字典,此处使用仅仅展示for嵌套for而已 #} {# {% for book in book_list1 %}#} {# <tr>#} {# {% for field,value in book.items %}#} {# <td>{{ field }} == {{ value }}</td>#} {# {% endfor %}#} {# </tr>#} {# {% endfor %}#} {# {% for book in book_list1 %}#} {# <tr>#} {# <td>{{ book.id }}</td>#} {# <td>{{ book.name }}</td>#} {# {% if book.price > 200 %}#} {# <td bgcolor="#ff7f50">{{ book.price }}</td>#} {# {% else %}#} {# <td>{{ book.price }}</td>#} {# {% endif %}#} {# </tr>#} {# {% endfor %}#} {# 逆向循环数据 #} {# {% for book in book_list1 reversed %}#} {# <tr>#} {# <td>{{ book.id }}</td>#} {# <td>{{ book.name }}</td>#} {# {% if book.price > 200 %}#} {# <td bgcolor="#ff7f50">{{ book.price }}</td>#} {# {% else %}#} {# <td>{{ book.price }}</td>#} {# {% endif %}#} {# </tr>#} {# {% endfor %}#} {% for book in book_list1 %} <tr> {# <td>{{ forloop.counter }}</td>#} {# <td>{{ forloop.counter0 }}</td>#} {# <td>{{ forloop.revcounter }}</td>#} {# <td>{{ forloop.revcounter0 }}</td>#} {# <td>{{ forloop.first }}</td>#} <td>{{ forloop.last }}</td> <td>{{ book.id }}</td> <td>{{ book.name }}</td> {% if book.price > 200 %} <td bgcolor="#ff7f50">{{ book.price }}</td> {% else %} <td>{{ book.price }}</td> {% endif %} </tr> {% endfor %} </table> </body> </html>
属性 |
|
---|---|
forloop.counter | 显示循环的次数,从1开始 |
forloop.counter0 | 显示循环的次数,从0开始 |
forloop.revcounter0 | 倒数显示循环的次数,从0开始 |
forloop.revcounter | 倒数显示循环的次数,从1开始 |
forloop.first | 判断如果本次是循环的第一次,则结果为True |
forloop.last | 判断如果本次是循环的最后一次,则结果为True |
forloop.parentloop | 在嵌套循环中,指向当前循环的上级循环 |
filter本质就是一个函数,这种函数,允许我们直接在模板中使用。使用过滤器的情况一般就是希望在模板中对数据进行格式化处理或对数据进行规范输出和调整。
文档: https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#ref-templates-builtins-tags
内置过滤器[build-in filter]
safe 声明当前视图提供的数据中,html代码不需要进行实体字符转义.
如果来自客户端的留言等信息,在是否使用safe时,一定要考虑清楚,可以提前清楚script等不全安的标签
语法格式: {{obj|filter:param}} #
1 add : 给变量加上相应的值 # #
2 addslashes : 给变量中的引号前加上斜线 # #
3 capfirst : 首字母大写 # #
4 cut : 从字符串中移除指定的字符 # #
5 date : 格式化日期字符串 # #
6 default : 如果值是False,就替换成设置的默认值,否则就是用本来的值 # #
7 default_if_none: 如果值是None,就替换成设置的默认值,否则就使用本来的值 #实例: #value1="aBcDe" {{ value1|upper }} #value2=5 {{ value2|add:3 }} #value3='he llo wo r ld' {{ value3|cut:' ' }} #import datetime #value4=datetime.datetime.now() {{ value4|date:'Y-m-d' }} #value5=[] {{ value5|default:'空的' }} #value6='跳转' {{ value6 }} {% autoescape off %} {{ value6 }} {% endautoescape %} {{ value6|safe }} {{ value6|striptags }} #value7='1234' {{ value7|filesizeformat }} {{ value7|first }} {{ value7|length }} {{ value7|slice:":-1" }} #value8='http://www.baidu.com/?a=1&b=3' {{ value8|urlencode }} value9='hello I am yuan'
用法 | 代码 | |
---|---|---|
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}} |
escape | 把内容中的HTML特殊符号转换成实体字符 | {{content | escape }} |
filesizeformat | 把文件大小的数值转换成单位表示 | {{filesize | filesizeformat}} |
join | 按指定字符拼接内容 | {{list| join("-")}} |
random | 随机提取某个成员 | {list | random}} |
slice | 按切片提取成员 | {{list | slice:":-2"}} |
truncatechars |
按字符长度截取内容 | {{content | truncatechars:30}} |
truncatewords | 按单词长度截取内容 |
customer filter
要声明自定义过滤器并且能在模板中正常使用,需要完成3个步骤。
-
确保当前需要使用过滤器的子应用已经注册到了INSTALLED_APPS中。
-
编写过滤器,过滤器必须在子应用下的templatetags包里面创建对应的python文件中。
from django import template # 返回值的变量名必须叫做register register = template.Library() # 自定义过滤器 @register.filter("sex") def check_sex(content): # 过滤器必须有一个以上的参数,提供给模板调用 if int(content): return "男" return "女"
3.在模板中通过load标签加载当前子应用已经声明的过滤器函数,load标签的使用最好写在模板的第一行。
{% load my_filters %}