本文为 Django 学习笔记,讲解模板的使用。

运行环境

  • Windows 10
  • Pycharm Community Edition 2020.1.3
  • Django 3.0.8

所有的代码见【Django】系列。

定义模板

变量

变量是视图传递给模板的数据,要遵守标识符规则。视图中的传递参数的键就是模板中的变量,语法 {{var}}

# views.py
def index(request):# return HttpResponse("Mike is so handsome!")return render(request, 'myApp/index.html', {"num": 10})
<!--index.html-->
<body><h1>Mike is a good man</h1><h1>num=*{{num}}*</h1>
</body>

如果使用的变量不存在,则插入的是空字符串。

在模板中使用点语法,首先将变量当作字典来查询,如果不是字典,则当作属性或方法,如果都不是则为数字索引。

在模板中调用对象:

<body><h1>Mike is a good man</h1><h1>{{stu.sname}}</h1><h1>num=*{{num}}*</h1>
</body>

在视图中进行传递:

def index(request):student = Students.objects.get(pk=1)return render(request, 'myApp/index.html', {"stu": student})

还可以在模板中调用对象的方法。首先在 models.py 中定义一个方法:

def getName(self):return self.sname

但是,在模板中不能传递参数。

标签

标签是用来在输出中创建文本的,并且可以控制逻辑和尊换。标签的语法为 {%tag%},无需缩进。

if

格式为:

<!--
{% if 表达式1 %}
语句1
{% elif 表达式2 %}
语句2
{% else %}
语句3
{% endif %}
-->{% if num %}<h1>if - Mike is a good man</h1>
{% endif %}

当 num 为 0 时,不显示。

for

<!--
{% for 变量 in 列表 %}
语句1
{% empty %} 列表为空时执行语句2
语句2
{% endfor %}{{ forloop.counter }}表示当前是第几次循环
--><body><h1>学生列表</h1><ul>{% for stu in students %}<li>{{forloop.counter}}--{{stu.sname}}--{{stu.sgrade}}</li>{% empty %}<l1>目前没有学生</l1>{% endfor %}</ul>
</body>

显示出 students 列表:

每行显示不同的颜色:

<body><h1>学生列表</h1><ul>{% for stu in students %}{% if forloop.counter|divisibleby:2%}<li style="color:red">{{forloop.counter}}--{{stu.sname}}--{{stu.sgrade}}</li>{% else %}<li style="color:blue">{{forloop.counter}}--{{stu.sname}}--{{stu.sgrade}}</li>{% endif %}{% empty %}<l1>目前没有学生</l1>{% endfor %}</ul>
</body>

效果为:

comment

作用是注释多行

{% comment %}
注释的内容
{% endcomment %}

ifequal, ifnotequal

用来判断是否相等,格式为:

{% ifequal 值1 值2 %}
语句
{% endifequal %}

如果值 1 等于值 2 则执行语句

include

加载模板并以标签内的参数渲染,格式为:

{% include 模板目录 参数1 参数2%}

后面会详细介绍。

url

反向解析,格式为:

{% url'namespace: name' p1 p2 %}

后面会详细介绍。

csrf_token

用于跨站请求伪造保护,格式为:

{% csrf_token %}

后面会详细介绍。

block, extends

用于模板的继承,后面会详细介绍。

autoescape

用于 HTML 转义,后面会详细介绍。

过滤器

在变量被显示前修改它,语法为 {{var|过滤器}}

  • lower、upper:将字符串过滤成小写/大写

    过滤器可以传递参数,参数用引号引起来。join 的格式为 列表|join:'#'

    <h1>{{list|join:'#'}}</h1>
    
  • 如果一个变量没有被提供,或值为 False、空,可以使用默认值 default,格式为 {{var|default:'good'}}

    <h1>{{test|default:'没有'}}</h1>
    
  • 根据给定格式转换日期为字符串,使用 date,格式为 {{ dateVal:'y-m-d'}}

  • HTML 转义:escape。后面详细介绍

  • 加减乘除

注释

单行注释:{# 注释内容 #}

多行注释:见 comment

反向解析

在主页中添加 a 标签,点击进入链接:

<a href="/good/">链接</a>

此时若将 project/url.py 中的主页匹配修改,则该标签无法定位到 good.html 页面。要将 a 标签中的路径修改为 /sunck/good/ 才能正常匹配到 url。但当 html 文件中有很多这样的路径时,修改十分不便,我们考虑使用反向解析技术(在 【Django 视图】有介绍)。a 标签中的路径通过两个 url 推理出来。

在 url 中配置如下:

# project/urls.py。使用namespace
re_path(r'^sunck/', include('myApp.urls', namespace="app")),
# myApp/urls.py
app_name = 'myApp' # Django2要加这句才能进行反向解析
# name最好与前面对应路径名
re_path(r'good/(\d+)/$', views.good, name="good"),

有了上面这几行代码,就可以动态生成 a 标签中的链接。上面写的 a 标签为硬链接,此时我们应该这样写:

{# 1为参数 #}
<a href="{% url 'app:good' 1 %}">链接</a>
{# 多参数形式 #}
<a href="{% url 'app:good' 1 2 %}">链接</a>

点击主页的链接后得到:

再将 project/urls.py 中的 sunck 删去,仍然可以正常匹配。

用一句话总结反向解析实际上就是给 2 个 url 起了个别名

模板继承

可以减少页面内容的重复定义,实现页面的重用。很多网站的 header 和 footer 是相同的,我们可以写一个继承来实现所有的 header 和 footer。我们可以使用 blockextends 标签实现模板继承。语法如下:

{% block 标签名 %}{% endblock 标签名 %}{% extends '父模板路径' %}

我们定义一个父模板和子模版。首先在 templates/myApp 下添加文件 base,html:

<head><meta charset="UTF-8"><title>Title</title><style>#header{width:100%;height:100px;background-color:red;}#footer{width:100%;height:100px;background-color:blue;}</style>
</head>
<body><div id="header">header</div><div id="main"> {# block继承 #}{% block main %}{% endblock main %}<hr/>{% block main2 %}{% endblock main2 %}</div><div id="footer">footer</div>
</body>
</html>

再在同路径下添加文件 main.html 和 detail.html:

{% main.html %}
{% extends 'myApp/base.html' %}{% block main %}<h1>Mike is a good man</h1>
{% endblock main %}{% block main2 %}<h1>Cathy is a cute girl</h1>
{% endblock main2 %}{% detail.html %}
{% extends 'myApp/base.html' %}{% block main %}<h1>Mike is a nice man</h1>
{% endblock main %}

效果如下:

HTML 转义

如果在 index 视图中返回一个 html 标签,程序会自动将其当作字符串:

return render(request, 'myApp/index.html', {"code": "<h1>Mike is a good man</h1>"})

如果我们要将接收的字符串当作 html 代码渲染,有 2 种方法:

{# safe过滤器 #}
{{code|safe}}{# autoescape标签 #}
{# 关闭自动转义即可将字符串当作html代码渲染 #}
{% autoescape off %}{{code}}
{% endautoescape %}

效果如下:

CSRF

跨站请求伪造。某些恶意网站包含链接、表单、按钮、js 会利用登录的用户在浏览器中认证,从而攻击服务。

我们提交表单进行用户登录。模板页面:

{# postfile.html #}
<body><form action="/showinfo/" method="post"><!--{% csrf_token %}-->姓名:<input type="text" name="username"/><hr/>密码:<input type="password" name="passwd"/><hr/><input type="submit" value="登录"/></form>
</body>{# showinfo.html #}
<body><h1>name:{{username}}</h1><h1>pass:{{passwd}}</h1>
</body>

对应视图:

def postfile(request):return render(request, 'myApp/postfile.html')
def showinfo(request):name = request.POST.get('username')pwd = request.POST.get('passwd')return render(request, 'myApp/showinfo.html',{"username": name, "passwd": pwd})

直接登录用户会报错 Forbidden:

程序进行 CSRF 验证的原因为:

当我们在网页中查看源代码:


)

将其中的代码拷贝到本地,存为 html 文件,并将 action 路径改为服务器的路径 http://127.0.0.1:8000/showinfo/

再将本地的 html 文件用浏览器打开,就可以进行表单提交:

在 settings.py 中会默认开启 CSRF 验证:

MIDDLEWARE = [# 'django.middleware.csrf.CsrfViewMiddleware',
]

注释掉这行代码,服务器和本地文件就都能登录了:

但是本地文件登录有很大的危险性,黑客可以写脚本无限循环登录,无数次在数据库中验证,攻击服务。

为了防止 CSRF,我们将上面的注释解开就好。但连自己的服务器都无法登录,可以在提交表单中加上:

{% csrf_token %}

这样以后,服务器就可以成功提交表单登录,而本地文件无法登录。但是,如果本地文件获取了 csrf 的 token 值,也可以伪装登录。查看服务器源代码可以得到 token 值:

将其添加到本地文件后,还是能够成功登录。在登录界面找到 token 的值为:

验证码

在用户注册、登录页面时使用,为了防止暴力请求,减轻服务器的压力,也是防止 csrf 的一种方式。

这里我们用代码生成一个验证码的图片:

def verifycode(request):# 引入绘图模块from PIL import Image, ImageDraw, ImageFont# 引入随机函数模块import random# 定义变量,用于画面的背景色、宽、高bgcolor = (random.randrange(20, 100), random.randrange(20, 100),random.randrange(20, 100))width = 100height = 50# 创建画面对象im = Image.new('RGB', (width, height), bgcolor)# 创建画笔对象draw = ImageDraw.Draw(im)# 调用画笔的point()函数绘制噪点for i in range(0, 100):xy = (random.randrange(0, width), random.randrange(0, height))fill = (random.randrange(0, 255), 255, random.randrange(0, 255))draw.point(xy, fill=fill)# 定义验证码的备选值str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'# 随机选取4个值作为验证码rand_str = ''for i in range(0,4):rand_str += str[random.randrange(0, len(str))]# 构造字体对象。这里找自己路径中的字体库即可,注意是ttf格式font = ImageFont.truetype(r'C:\Windows\Fonts\Arial.ttf', 40)# 构造字体颜色fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))# 绘制4个字draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)# 释放画笔del draw# 存入session,用于做进一步验证# request.session['verify'] = rand_str# 内存文件操作import iobuf = io.BytesIO()# 将图片保存在内存中,文件类型为.pngim.save(buf, 'png')# 将内存中的图片数据返回给客户端,MIME类型为图片pngreturn HttpResponse(buf.getvalue(), 'image/png')

注意要提前用 pip install pillow 安装 pillow。调用该视图得到:

然后我们写一个输入验证码登录的模板 verifycodefile.html:

<body><form method="post" action="/verifycodecheck">{% csrf_token %}<input type="text" name="verifycode"/><img src="/verifycode/"/><input type="submit" value="登录"></form>
</body>

配置 url 后得到结果:

点击登录按钮,判断验证码是否正确,并显示相应提示。verifycodecheck 的视图如下:

from django.shortcuts import render, redirect
def verifycodecheck(request):code1 = request.POST.get("verifycode").upper() # 不区分大小写code2 = request.session["verify"].upper() if code1 == code2: # session中缓存的验证码与输入的验证码对比return render(request, 'myApp/success.html')else:return redirect('/verifycodefile/')

输入正确的验证码后:

输入错误时要进行提示。在模板中加 span 标签:

<span>{{flag}}</span>

在视图函数中对验证码进行验证:

from django.shortcuts import render, redirect
def verifycodefile(request):f = request.session.get("flag", True) # 若首次取得flag,则为Truestr = ""if f == False:str = "请重新输入"request.session.clear() # 清空sessionreturn render(request, "myApp/verifycodefile.html", {"flag": str})
def verifycodecheck(request):code1 = request.POST.get("verifycode").upper()code2 = request.session["verify"].upper()if code1 == code2:return render(request, 'myApp/success.html')else:request.session["flag"] = False # 将flag域置Falsereturn redirect('/verifycodefile/')

输入错误的验证码后:

至此,关于 Django 模板的知识就介绍完啦。

【Django】模板相关推荐

  1. Django 模板4.1

    模板介绍 作为Web框架,Django提供了模板,可以很便利的动态生成HTML 模版系统致力于表达外观,而不是程序逻辑 模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视 ...

  2. Django模板过滤器详解

    Django 模板过滤器也是我们在以后基于 Django 网站开发过程中会经常遇到的,如显示格式的转换.判断处理等.以下是 Django 过滤器列表,希望对为大家的开发带来一些方便. 一.形式:小写 ...

  3. django模板的导入

    模板导入 前提:多个页面有一个相同的页面版块(多个有样式标签的集合体) 如何运用:可以将多个样式标签的集合进行封装对外提供版块的名字(接口),在有该版块的页面中直接导入即可 语法:{% include ...

  4. Django模板、配置文件、静态文件及案例实现(创建模板、设置模板查找路径、模板接收视图传入的数据、模板处理数据、BASE_DIR、DEBUG、本地语言与时区、App应用配置)

    1.Django模板 网站如何向客户端返回一个漂亮的页面呢? 漂亮的页面需要html.css.js. 可以把这一堆字段串全都写到视图中, 作为HttpResponse()的参数,响应给客户端. 存在的 ...

  5. Django模板用法

    django模板原理 # 创建template对象,由context对象传递template所需要的值, 有render方法进行模板的呈现 # 写模板,创建 Template 对象,创建 Contex ...

  6. django模板过滤器

    django模板&过滤器 声明:部分信息来源这篇博客https://www.cnblogs.com/maple-shaw/articles/9333821.html MVC: 模型(model ...

  7. python django 模板

    1 用两个大括号括起来的文字{{person_name}} 称为变量 2 被 大括号和面分号包围的文件({% if ordered_warranty %})是模板标签 3 过滤器是用管道符(|) 和U ...

  8. Django—模板渲染

    参考文档: http://www.cnblogs.com/fnng/p/4373108.html https://code.ziqiangxuetang.com/django/django-intro ...

  9. Django模板语言(译)

    原文地址:https://docs.djangoproject.com/zh-hans/2.1/ref/templates/language/ 翻译日期:2019年3月8日-2019年3月9日 by: ...

  10. Django 3.2.5博客开发教程:体验django模板

    上面我们有说过,用户发送请求的时候,视图会返回一个响应,响应可以是一个重定向,一个404错误,一个XML文档,一张图片或者是一个HTML内容的网页.前面几个返回的信息比较有限,我们重点更多是放在HTM ...

最新文章

  1. HDOJ-1062 Text Reverse
  2. java哈夫曼编码与译码_哈夫曼编码与译码
  3. ProgressDialog用法详解
  4. oauth2 单点登录_Spring Security Oauth2和Spring Boot实现单点登录
  5. List的remove(对象)操作有时候会报ConcurrentModificationException异常
  6. CSS中em和px单位的区别(转)
  7. 产品经理必知的数据指标
  8. php多功能引流工具箱源码
  9. 预训练新范式!为什么Prompt会更有效?
  10. xml中出现“文档中根元素后面的标记必须格式正确” 的错误
  11. vector容器——容量和大小
  12. matlab用ezplot绘制参数方程,MATLAB学习1 之画图函数
  13. android开源进度条,Android github开源进度条类框架SmoothProgressBar的使用
  14. 学子商城实训项目总结
  15. 莫烦python 强化学习 (Reinforcement Learning)
  16. python课程的中期报告范文_毕业论文中期报告范文(毕业论文中期检查范文8篇)...
  17. shell脚本分析cctv 央视 shtml 获取 m3u8链接,每天自动下载2k超清版本《新闻联播》以便未能按时收看时学习跟进
  18. 摄像头直播视频接口视频播放器
  19. Leetcode - 1103. 分糖果 II 排排坐,分糖果。
  20. 质数/素数筛选c++超简单版写法

热门文章

  1. JS数组Arry 操作方法速记
  2. 本科课程【java程序设计】实验2 - 类与对象编程练习
  3. springboot项目下关于网站访问量UV统计
  4. 微信小程序设置解锁密码
  5. Excel VBA语句集300
  6. 尚硅谷-微信小程序文档
  7. 手写图片缓存框架 ImageLoader
  8. vue中防止按钮重复点击提交的方法
  9. [UOJ UNR #2]积劳成疾
  10. Dubbo的Api+Provider+Customer示例(IDEA+Maven+Springboot+dubbo)