【一】引子
来看一段代码
def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)
直接把HTML页面嵌套在视图函数里返回给浏览器并不是一个好主意;
原因:
- 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改,牵一发而动全身;
- Python 代码编写和 HTML 设计是两项不同的工作,前端开发和后端开发无非 并行;
 基于这些原因,将HTML页面的设计和后端逻辑设计分离,会更简洁、容易维护开发我们的WEB应用。 我们可以使用 Django的 模板系统 (Template System)来实现这种模式。这个就是DJango模板系统的意义所在。
【二】模板语法的传值
- {{ }}: 变量相关
- {% %}: 逻辑相关
重要事项:
- 变量语法:在模板中使用变量时,使用双花括号{{ }}将变量包围起来,例如{{ variable_name }}。
- 变量名称:变量名称由字母、数字、下划线和点号组成,不能以数字开头。
- 变量上下文:变量的值来自于视图函数中的上下文(context),在模板中可以直接访问视图函数中传递的变量。
- 对象属性:如果变量是一个对象,可以使用点号语法来访问对象的属性,例如{{ object.attribute }}。
- 字典和列表:可以使用方括号语法来访问字典和列表中的元素,例如{{ my_dict["key"] }}或{{ my_list[0] }}。
- 过滤器:可以使用管道符号|将变量与过滤器组合,以修改变量的显示方式,例如{{ variable|filter_name }}。
- 默认值:可以通过在变量后面添加default过滤器来提供默认值,以防变量不存在或为空,例如{{ variable|default:"N/A" }}。
【1】 变量

(1)传值
- 在Django的模板语言中按此语法使用: 
  - {{ 变量名 }}。
 
- 当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。
- 变量的命名包括任何字母数字以及下划线 (“_”)的组合。
- 变量名称中不能有空格或标点符号。
(2)取值
- 点(.)在模板语言中有特殊的含义。 
  - 当模版系统遇到点(“.”),它将以这样的顺序查询: 
    - 字典查询(Dictionary lookup)
- 属性或方法查询(Attribute or method lookup)
- 数字索引查询(Numeric index lookup)
 
 
- 当模版系统遇到点(“.”),它将以这样的顺序查询: 
    
总结:
 通过在模板中使用双花括号{{ }}来传递变量,并使用点.来取值,您可以在模板中动态地显示来自视图函数的数据。
注意事项
- 如果计算结果的值是可调用的,它将被无参数的调用。 调用的结果将成为模版的值。
- 如果使用的变量不存在, 模版系统将插入 string_if_invalid 选项的值, 它被默认设置为’’ (空字符串) 。
简单的示例:
以下是Django模板系统中的八大数据类型的简单表示,并包括了urls.py路由层、views.py视图层和前端HTML的示例:
-  字符串(String): - urls.py:无需特殊处理。
- views.py:将字符串传递给模板。
- HTML:直接在模板中使用变量。
 示例: # urls.py from django.urls import path from . import views urlpatterns = [ path('hello/', views.hello_view, name='hello'), ]# views.py from django.shortcuts import render def hello_view(request): greeting = "Hello, World!" return render(request, 'hello.html', {'greeting': greeting})<!-- hello.html --> <h1>{{ greeting }}</h1>
-  整数(Integer): - urls.py:无需特殊处理。
- views.py:将整数传递给模板。
- HTML:直接在模板中使用变量。
 
-  浮点数(Float): - urls.py:无需特殊处理。
- views.py:将浮点数传递给模板。
- HTML:直接在模板中使用变量。
 
-  列表(List): - urls.py:无需特殊处理。
- views.py:将列表传递给模板。
- HTML:使用循环在模板中遍历列表元素。
 
-  字典(Dictionary): - urls.py:无需特殊处理。
- views.py:将字典传递给模板。
- HTML:使用点号语法在模板中访问字典的键值对。
 
-  元组(Tuple): - urls.py:无需特殊处理。
- views.py:将元组传递给模板。
- HTML:直接在模板中使用变量。
 
-  对象(Object): - urls.py:无需特殊处理。
- views.py:将对象传递给模板。
- HTML:使用点号语法在模板中访问对象的属性或方法。
 
-  布尔值(Boolean): - urls.py:无需特殊处理。
- views.py:将布尔值传递给模板。
- HTML:使用条件语句在模板中根据布尔值显示不同的内容。
 
具体示例:
# urls.py文件
path('index/',views.index)
# views.py
def index(request):
    # 模板语法可以传递的后端python的数据类型
    int = 123
    float = 123.02
    str_ = '老子明天不上班'
    bool = True
    list = ['一号技师','二号技师','三号技师']
    tuple = (123,456,789,741,852,963)
    dict = {'username':'xiaoshuai','age': 18,'slary': 10000}
    set = {123,'数字','小明'}
    return render(request, 'index.html',locals())
<!-- 在index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板层传值</title>
</head>
<body>
{{ int }} <br>
{{ float }}<br>
{{ str }}<br>
{{ bool }}<br>
{{ list }}<br>
{{ tuple }}<br>
{{ dict }}<br>
{{ set }}<br>
</body>
</html>

- 跟进上述来看跟保证输出成功的参数就是locals()
return render(request, 'index.html',locals())
值得注意的是:
 函数也能
-  def bai(): x = 6 y = 7 z = x + y return z
-  传递函数名会自动加括号调用 但是模板语法不支持给函数额外的参数:{{ bai }} 
-  传类名的时候也会自动加括号调用(实例化){{ Myclass }} ,{{ obj }} 
-  内部能够自动判断出当前的变量名是否可以加括号电影 如果可以就会自动执行 这针对是函数名跟类名。 
-  {{ obj.get_bai }} <br> {{ obj.get_func }} <br> {{ obj.get_class }} <br>
-  对象被展示到html页面上 就类似于执行了打印操作也会触发 __self__方法

    class Myclass(object):
        def get_bai(self):
            return 'sorry get_bai'
        @staticmethod
        def get_func():
            return 'sorry get_func'
        @classmethod
        def get_class(cls):
            return 'sorry clsssss'
        def __str__(self):
            return '也可以被执行'
    obj = Myclass()
    return render(request, 'index.html',locals())


取值
- 在Django模板语法的取值, 是固定的格式 只能采取句点号 ( . )
<p> {{ dict.hobby.1 }}</p>
<p>{{ list.0 }}</p>
<p>{{ tuple.4 }}</p>
<p>{{ set.2 }}</p>
- 即可以点健也可以点索引, 还可以两者混用。
【三】过滤器
【1】过滤器
- 在Django的模板语言中,通过使用 过滤器 来改变变量的显示。
(1)过滤器的语法
- {{ value|filter_name:参数 }}
- {{ 数据|过滤器:参数 }}
- 使用管道符"|"来应用过滤器。
- 例如: 
  - {{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。
- lower在这里的作用是将文本全都变成小写。
 
(2)注意事项
- 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
- 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
- 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
- |左右没有空格!没有空格!没有空格!
Django的模板语言中提供了大约六十个内置过滤器。
【2】语法
{{数据|过滤器:参数}}
【3】Django中实战使用——常用的过滤器:
①项目目录下的views.py文件:
from django.shortcuts import render
from django.http import HttpResponse
from datetime import datetime
def index(request):
    test="THIS IS A LIST!"
    list=["A","B","C","D","E"]
    data={
        'test':test,
        'xx':'',
        'num1':1,
        'num2':2,
        'list':list,
        'now':datetime.now(),
        'html':'<h1>hello django!!!</h1>',
        'float':3.1415926
    }
    return render(request, "index.html", data)
②项目目录下templates模板文件夹下的模板文件index.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试!</title>
</head>
<body>
{#没做处理的变量:#}
{{ test }}<br>
{#设置了默认值的变量  在这个值被django认为是False的时候会使用此默认值。比如:空字符串,None。#}
{{ xx|default:'xxxxx' }}<br>
{#设置了只有为None时才使用默认值的变量#}
{{ xx|default_if_none:'aaaaa'}}<br>
{#变为小写后的变量#}
{{ test|lower }}<br>
{#先变为小写再将首字母大写后的变量#}
{{ test|lower|capfirst }}<br>
{#两个数字变量相加   add:字符串相加,数字相加,列表相加,如果失败,将会返回一个空字符串#}
{{ num1|add:num2 }}<br>
{#两个字符串变量相加#}
{{ test|add:xx }}<br>
{#列表变量的第一个元素#}
{{ list|first }}<br>
{#列表变量的最后一个元素#}
{{ list|last }}<br>
{#默认的data日期时间格式#}
{{ now|date }}<br>
{#默认的time时间格式#}
{{ now|time }}<br>
{#这是data过滤器的年月日24小时制时间格式#}
{{ now|date:'Y/m/d/H:i:s' }}<br>
{#这是time过滤器的时分秒12小时制时间格式#}
{{ now|time:'h:i:s' }}<br>
{#这是字符串的join方法  跟python中join一样的用法#}
{{ list|join:'oooo' }}<br>
{#这是字符串的长度方法#}
{{ test|length }}<br>
{#这是列表的长度是否为4#}
{{ list|length_is:4 }}<br>
{#下面这俩有xxx.html类型的,针对html,截断标签中的字符,而不会截断标签#}
{#这是字符串只显示4个字符,其余省略(但是占3位)#}
{{ test|truncatechars:7 }}<br>
{#这是字符串只显示2个单词,其余省略(不占位)#}
{{ test|truncatewords:2 }}<br>
{#这是字符串的切片#}
{{ test|slice:'1:4' }}<br>
{#这是列表的切片#}
{{ list|slice:'2' }}<br>
{#这是含html标签的字符串#}
{{ html }}<br>
{#这是去掉字符串中的html标签#}
{{ html|striptags }}<br>
{#这是关掉自动转义,使字符串中html标签生效#}
{{ html|safe }}<br>
{#这是没做处理的小数#}
{{ float }}<br>
{#这是保留了一位小数#}
{{ float|floatformat }}<br>
{#这是保留了两位小数#}
{{ float|floatformat:'2' }}
</body>
</html>
【4】日期格式化(date)
(1)语法
- 格式化
{{ value|date:"Y-m-d H:i:s"}}
- 可用的参数:
| 格式化字符 | 描述 | 示例输出 | 
|---|---|---|
| a | 'a.m.'或'p.m.'(请注意,这与PHP的输出略有不同,因为这包括符合Associated Press风格的期间) | 'a.m.' | 
| A | 'AM'或'PM'。 | 'AM' | 
| b | 月,文字,3个字母,小写。 | 'jan' | 
| B | 未实现。 | |
| c | ISO 8601格式。 (注意:与其他格式化程序不同,例如“Z”,“O”或“r”,如果值为naive datetime,则“c”格式化程序不会添加时区偏移量(请参阅 datetime.tzinfo) 。 | 2008-01-02T10:30:00.000123+02:00或2008-01-02T10:30:00.000123如果datetime是天真的 | 
| d | 月的日子,带前导零的2位数字。 | '01'到'31' | 
| D | 一周中的文字,3个字母。 | “星期五” | 
| e | 时区名称 可能是任何格式,或者可能返回一个空字符串,具体取决于datetime。 | ''、'GMT'、'-500'、'US/Eastern'等 | 
| E | 月份,特定地区的替代表示通常用于长日期表示。 | 'listopada'(对于波兰语区域,而不是'Listopad') | 
| f | 时间,在12小时的小时和分钟内,如果它们为零,则分钟停留。 专有扩展。 | '1','1:30' | 
| F | 月,文,长。 | '一月' | 
| g | 小时,12小时格式,无前导零。 | '1'到'12' | 
| G | 小时,24小时格式,无前导零。 | '0'到'23' | 
| h | 小时,12小时格式。 | '01'到'12' | 
| H | 小时,24小时格式。 | '00'到'23' | 
| i | 分钟。 | '00'到'59' | 
| I | 夏令时间,无论是否生效。 | '1'或'0' | 
| j | 没有前导零的月份的日子。 | '1'到'31' | 
| l | 星期几,文字长。 | '星期五' | 
| L | 布尔值是否是一个闰年。 | True或False | 
| m | 月,2位数字带前导零。 | '01'到'12' | 
| M | 月,文字,3个字母。 | “扬” | 
| n | 月无前导零。 | '1'到'12' | 
| N | 美联社风格的月份缩写。 专有扩展。 | 'Jan.','Feb.','March','May' | 
| o | ISO-8601周编号,对应于使用闰年的ISO-8601周数(W)。 对于更常见的年份格式,请参见Y。 | '1999年' | 
| O | 与格林威治时间的差异在几小时内。 | '+0200' | 
| P | 时间为12小时,分钟和’a.m。'/‘p.m。’,如果为零,分钟停留,特殊情况下的字符串“午夜”和“中午”。 专有扩展。 | '1 am','1:30 pm' / t3>,'midnight','noon','12:30 pm' / T10> | 
| r | RFC 5322格式化日期。 | 'Thu, 21 Dec 2000 16:01:07 +0200' | 
| s | 秒,带前导零的2位数字。 | '00'到'59' | 
| S | 一个月的英文序数后缀,2个字符。 | 'st','nd','rd'或'th' | 
| t | 给定月份的天数。 | 28to31 | 
| T | 本机的时区。 | 'EST','MDT' | 
| u | 微秒。 | 000000to999999 | 
| U | 自Unix Epoch以来的二分之一(1970年1月1日00:00:00 UTC)。 | |
| w | 星期几,数字无前导零。 | '0'(星期日)至'6'(星期六) | 
| W | ISO-8601周数,周数从星期一开始。 | 1,53 | 
| y | 年份,2位数字。 | '99' | 
| Y | 年,4位数。 | '1999年' | 
| z | 一年中的日子 | 0到365 | 
| Z | 时区偏移量,单位为秒。 UTC以西时区的偏移量总是为负数,对于UTC以东时,它们总是为正。 | -43200到43200 | 
【5】取消转义(mark_safe和safe)
- Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。
- 但是有的时候我们可能不希望这些HTML元素被转义
- 比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。
- 以后在写全栈项目时,前端代码不一定必须在前端页面书写
- 也可以选择先在后端写好,再传递给前端页面展示
(1)前端转义(safe)
msg = '<h1>鸡你太美</h1>'
<p>转义字符(不转义) {{ msg }}</p>
<p>转义字符(转义) {{ msg|safe }}</p>
转义字符(不转义) <h1>鸡你太美</h1>
转义字符(转义)
鸡你太美(已变成h1标题格式)
(2)后端转义(mark_safe)
from django.utils.safestring import mark_safe
res = mark_safe('<h1>坤坤</h1>')
<p>转义字符(转义) {{ res }}</p>
转义字符(转义)
坤坤(已变成h1标题格式)
-  前端 -  msg = '<h1>你太美</h1>'
-  {{ 值| safe}}
 
-  
-  后端 -  from django.utils.safestring import mark_safe
-  res = mark_safe("<h1>你太美</h1>")
 
-  
转义字符(转义) {{ msg|safe }}
转义字符(不转义)鸡你太美
转义字符(转义)
鸡你太美(已变成h1标题格式)
### (2)后端转义(mark_safe)
```java
from django.utils.safestring import mark_safe
res = mark_safe('<h1>坤坤</h1>')
<p>转义字符(转义) {{ res }}</p>
转义字符(转义)
坤坤(已变成h1标题格式)
-  前端 -  msg = '<h1>你太美</h1>'
-  {{ 值| safe}}
 
-  
-  后端 -  from django.utils.safestring import mark_safe
-  res = mark_safe("<h1>你太美</h1>")
 
-  



















