模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术
静态网页:页面上的数据都是写死的,万年不变
动态网页:页面上的数据是从后端动态获取的(后端获取数据库数据然后传递给前端页面)
对模板引擎的一般支持和Django模板语言的实现都存在于 django.template 命名空间中
Django模板只是一个文本文档或使用Django模板语言标记的Python字符串。一些结构被模板引擎识别和解释,主要的是变量( {{ 变量 }} )和标签( {% 标签 %}
)。
Django框架中内置了web开发领域非常出名的一个DjangoTemplate模板引擎(DTL)
DTL官方文档
要在django框架中使用模板引擎把视图中的数据更好的展示给客户端,需要完成3个步骤:
- 在项目配置文件中指定保存模板文件的模板目录。一般模板目录都是设置在项目根目录或者主应用目录下。
- 在视图中基于django提供的渲染函数绑定模板文件和需要展示的数据变量
- 在模板目录下创建对应的模板文件,并根据模板引擎内置的模板语法,填写输出视图传递过来的数据。
在当前项目根目录下**创建模板templates文件夹
.**
在**settings.py
配置文件中配置模板,找到TEMPLATES配置项,填写DIRS设置模板目录
**
'DIRS': [os.path.join(BASE_DIR, 'templates')],
- BACKEND:是实现Django模板后端API的模板引擎类的路径。内置是django.template.backends.django.DjangoTemplates和 django.template.backends.jinja2.Jinja2(使用这个需要额外安装jinja2库)
- DIRS :按搜索顺序定义引擎应该查找模板源文件的目录列表
- APP_DIRS:告诉引擎是否应该在已安装的应用程序中查找模板,每个后端为其模板应存储在的应用程序内的子目录定义一个常规名称。
- OPTIONS:包含后端特定的设置
Django模板
语言的语法主要涉及四个构造:变量、标签、过滤器、注释
一个变量从上下文中输出一个值,这是一个类似字典的对象将键映射到值。
变量需要使用
两对{{ 变量 }} 包裹
语法:{{ 变量名 }}
- 变量名称由:字母、数字、下划线组成
- 注意不能以下划线(_)开头
- 变量名称中不能包含空格或标点符号(特殊符号
.
除外)
案例:
在试图函数中,我有以下几个变量想要渲染到页面上
name = "张三"
age = 22
lists = [1, 2, 3, '法外狂徒']
dicts = {'name': '迪丽热巴', 'age': 22}
现在我需要将以上几个变量渲染展示在网页中,应该怎样写?
之前我们学习到想要返回一个页面使用
render
,其实render
中可以传递一个参数,供网页使用
def index_te(request):
name = "张三"
age = 22
lists = [1, 2, 3, '法外狂徒']
dicts = {'name': '迪丽热巴', 'age': 22}
return render(request, 'index_te.html',
{'name': name,
'age': age,
'lists': lists,
'dicts': dicts
})
在html网页中使用如下:
渲染单个变量
<p>{{name}}p>
<p>{{age}}p>
<p>{{lists}}p>
<p>{{dicts}}p>
遍历列表 lists
{% for i in lists %}
{{ forloop.counter }} -- {{ i }}
{% endfor %}
遍历字典 dicts
{% for key,value in dicts.items %}
{{key}}:{{value}}
{% endfor %}
我们在这里使用了 for 循环,其实在django的Template模板中的标签
深度查询
比如:
[1, 2, 3, 4, 5, 6, 7, ['a', 'b', 'c', [1, 'xx', 3]]]
我需要在页面中取出 xx
这个数据,应该怎样取?
深度查询:{{sd.7.3.1}}
通过句点符号
.
深度查询(执行函数也是如此)
标签在渲染过程中提供任意的逻辑。比如我们在刚才使用的 for
标签
详细的 Template 标签如下链接
Template 标签参考
在使用某些标签时需要同时使用开头和结尾标签,比如:if 和 for
{% for %} 代码 {% endfor %}
在使用时可以加上 无参数标签
csrf_token
这个标签是用于html进行 form 表单提交时,包含一个 随机变化的字符串
作用是用于防止跨域攻击
{% csrf_token %} {% cycle 'odd' 'even' %}
Django模板中比较常用的几个标签:
if
标签:用于逻辑判断for
标签:用于循环遍历autoescape
标签:自动转义url
标签:定义链接now
标签:显示当前时间if
标签案例:
在页面上去判断age是否大于10
:
{% if age > 10 %}
age大于10
{% else %}
age太小了
{% endif %}
如果没有空格,那么就会报错
Django模板内置了过滤器
过滤器,就是按照某种格式或者要求进行过滤
语法:
{{ name | 过滤器名称 : 过滤器参数 }}
|
字符表示串联管道,用于将变量和过滤器串联起来
如:
{{ value | add :"2"}}
这个过滤器将首先尝试将两个值强制转为整数。如果失败了,它将尝试将两个值加在一起。这对某些数据类型(字符串、列表等)有效,而对其他类型则失败。如果失败,结果将是一个空字符串。
如果 value =4
那么将输出 6
如:
{{ first|add:second }}
first
是[1, 2, 3]
并且second
是[4, 5, 6]
,则输出为[1, 2, 3, 4, 5, 6]
一些常用的过滤器:
过滤器 | 含义 | 用法 |
---|---|---|
date | 日期格式化 | {{ value | date:“Y-m-d H:M:S” }} |
defualt | 当变量没有值的情况下, 系统输出默认值 | {{ value | default=“默认值” }} |
length | 获取数据的长度 | {{ value | length}} |
random | 随机返回列表中的数 | {{ list | random }} |
safe | 让系统不要对内容中的html代码进行实体转义(将字符正常显示) | {{ htm l content | safe}} |
striptags | 去除html标签 | {{ value|striptags }} |
truncatechars | 如果一个字符串的长度超过指定的字符数,则截断它。截断后的字符串将以一个可翻译的省略号(“…”)结束。 | {{ value|truncatechars:7 }} |
add | 两数相加 | {{ value|add:“2” }} |
案例:
def filter_ts(request):
"""过滤器 filters"""
content = "重庆信息技术职业学院-软件学院"
# content1 = ''
from datetime import datetime
now = datetime.now()
content2 = "hello wrold!"
return render(request, "filter_ts.html", locals())
{{ content | safe }}
{{ content1 | safe }}
{# 过滤器本质就是函数,但是模板语法不支持小括号调用,所以需要使用:号分割参数 #}
{{ now | date:"Y-m-d H:i:s" }}
{{ conten1 | default:"默认值" }}
{# 一个数据可以连续调用多个过滤器 #}
{{ content2 | truncatechars:6 | upper }}
虽然官方已经提供了许多内置的过滤器给开发者,但是很明显,还是会有存在不足的时候。
例如:希望输出用户的手机号码:13512345678
显示:135*****678
.
这时我们就需要自定义过滤器。
自定义模板标签和过滤器参考
要声明自定义过滤器步骤:
templatetags(必须包含__init__.py)
** 目录,与 models.py
, views.py
等同级my_filters
**模块必须包含一个名为 register
的模块级变量,它是一个 template.Library
实例(固定写法)from django import template
register = template.Library()
# 自定义过滤器-用于隐藏电话号码
@register.filter("mobile")
def mobile(content):
return content[:3] + "*****" + content[-3:]
{% load my_filters %}
具体使用:
自定义过滤器 my_filters.py
:
视图函数 my_filters.py
:
templates 模板中使用:
实现效果:
自定义标签实现步骤和自定义过滤器一样,只是注册的写法不同
# 自定义过滤器
@register.filter
# 自定义标签
@register.simple_tag
模板继承可以让我们多个html页面继承同一个页面(也就是父页面),让我们页面布局更加统一。
比如:网页的头部和尾部内容一般都是一致的,我们就可以通过模板继承来实现复用。
传统的模板分离技术,依靠{% include “模板文件名”%} 实现,将页面嵌入到另一个页面中。
虽然达到了页面代码复用的效果,但是由此也会带来大量的碎片化模板,导致维护模板的成本上升。
所提Django框架中除了提供这种模板分离技术以外,还并行的提供了 模板继承给开发者.
父模板用于放置可重复利用的内容,子模板继承父模板的内容,并放置自己的内容。
{% include "模板文件名"%} # 模板嵌入
{% extends "base.html" %} # 模板继承
先来定义一个 base 父模板 templates/base.html
:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>base父模板title>
head>
<body>
<h1>base.html的头部h1>
<h1>base.html的内容h1>
<h1>base.html的脚部h1>
body>
html>
定义视图 app01/views.py
:
def extends_tp(request):
"""模板继承"""
return render(request,'extends_tp.html',locals())
设置路由 app01/urls.py
:
re_path('extends_tp/',views.extends_tp)
定义子模版 templates/extends_tp.html
:
{% extends "base.html" %}
运行:
{%block %} 子模版重写父模板内容 {%endblock%}
{{block.super}} # 使用父模板内容
标签 block…endblock: 是父模板中的预留区域,该区域留给子模板填充差异性的内容,不同预留区域名字不能相同。
{% block 名称 %}
预留给子模板的区域,可以设置设置默认内容
{% endblock 名称 %}
子模板如果没有设置父模板预留区域的内容,则使用在父模板设置的默认内容,当然也可以都不设置,就为空。
子模板设置父模板预留区域的内容:
{ % block 名称 % }
内容
{% endblock 名称 %}
重新定义一个 base 父模板 templates/base1.html
:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> {%block title %} base1父模板 {% endblock %}title>
head>
<body>
<h1>base1.html的头部h1>
{% block content %}
<h1>base1.html的内容h1>
{% endblock %}
<h1>base1.html的脚部h1>
body>
html>
定义视图 app01/views.py
:
def extends_tp1(request):
"""子模板重写父模板内容"""
return render(request, 'extends_tp1.html', locals())
设置路由 app01/urls.py
:
re_path('extends_tp1/',views.extends_tp1),
定义子模版 templates/extends_tp1.html
:
{% extends "base1.html" %}
{% block title %} extends_tp1.html的标题 {% endblock %}
{% block content %}
{{ block.super }} {# 父级模板同名block标签的内容 #}
extends_tp1.html的独立内容
{{ block.super }}
{% endblock %}
运行:
注意事项:
如果你在模版中使用
{% extends %}
标签,它必须是模版中的第一个标签(不然会报错)。在base模版中设置越多的
{% block %}
标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。为了更好的可读性,你也可以给你的
{% endblock %}
标签一个 名字 。例如:{% block content %} {% endblock content %}
,
在大型模版中,这个方法帮你清楚的看到哪一个
{% block %}` 标签被关闭了。不能在一个模版中定义多个相同名字的
block
标签。如果需要从父模板中获取块的内容,则使用 {{ block.super }}
主要是使用 css、javascript和图片文件。
开发中在开启了debug模式时,django可以通过配置,允许用户通过对应的url地址访问django的静态文件。
主应用setting.py
配置:
STATIC_URL = '/static/' # django模板中,可以引用{{STATIC_URL}}变量避免把路径写死。
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
总路由配置(主应用路由设置):
# 对外提供访问静态文件的路由,serve_static 是django提供静态访问支持的映射类。依靠它,客户端才能访问到django的静态文件。
path(r'static/' , server_static, {'document_root': settings.STATICFILES_DIRS})
总路由配置可不写
注意:项目上线以后,关闭debug模式时,django默认是不提供静态文件的访问支持,项目部署的时候,我们会通过收集静态文件使用nginx这种web服务器来提供静态文件的访问支持。