05-Django模板

一、模板概述

  • 模板组成
HTML代码
动态插入的代码(挖坑、填坑逻辑控制代码)
  • 作用
快速生成HTML页面
  • 优点
模板的设计实现了业务逻辑与现实内容的分离
视图可以使用任何模板
  • 模板处理
加载
渲染

二、定义模板

  • 变量
- 视图传递给模板的数据
- 变量遵守标识符规则
- 语法
  {{ var }}
- 注意
  变量若不存在,则插入空的字符串
- 点语法
 字典查询、属性或方法、数字索引 
  • 标签
- 语法
  {% tag %}
- 作用
  在输出中创建文本
  控制逻辑和循环
  • 单行注释
{# 注释内容 #}
  • 标签if
- 语法1
  {% if 条件 %}
      语句
  {% endif %}
- 语法2
  {% if 条件 %}
      语句1
  {% else %}
      语句2
  {% endif %}
- 语法3
  {% if 条件 %}
      语句1
  {% elif 条件 %}
      语句2
  {% elif 条件 %}
      语句3
  ....
  {% else %}
      语句
  {% endif %}
- 例如
  {% if username %}
      欢迎 <span> {{username}} </span> 回来
  {%else%}
      游客登录,新用户注册有惊喜!
  {%endif%}
  • 标签for
- 格式1
  {% for 变量 in 列表 %}
      语句
  {% endfor %}
- 格式2
  {% for 变量 in 列表 %}
      语句1
  {% empty %}
      语句2
  {% endfor %}
  备注: 列表为空或列表不存在时执行语句2
- 格式3
  {{forloop.counter}} 表示当前是第几次循环
- 例如
  {% for student in students %}
      <li>
          我叫{{student.sname}},性别{{student.ssex}},今年{{student.sage}}岁,座右铭:"{{student.sbrief}}"。
      </li>
  {% endfor %}
- 例如
  <ul>
      {% for name in names %}
          {% if forloop.counter|divisibleby:2 %}
              <li style="color: red"> {{forloop.counter}} - {{name}} </li>
          {% else %}
              <li style="color: blue"> {{forloop.counter}} - {{name}} </li>
          {% endif %}
      {% empty %}
          <li> 没有学生喔. </li>
      {% endfor %}
  </ul>
  • 标签comment
- 作用
  多行注释
- 例如
  {% comment %}
      <p>姓名: {{student.sname}}</p>
      <p>性别: {{student.ssex}}</p>
      <p>年龄: {{student.sage}}</p>
      <p>座右铭: {{student.sbrief}} </p>
  {% endcomment %}
  • 标签ifequal、ifnotequal
- 作用
  判断值1与值2是成立
- 例如
  {% ifequal 'hello' 'world' %}
      <h1> 喔,hello和world一样呢。 </h2>
  {% endifequal %}
- 例如
  # return render(request, 'meituan/testtemp.html',{'class1':'python03','class2':'python03'})
  {% ifequal class1 class2 %}
      <p>你们在同一个班级呢。</p>
  {% else %}
      <p>你们是不同班级。</p>
  {% endifequal %}
  • 过滤器
- 作用
  在变量被显示前修改它
- 语法
  {{ var|过滤器 }}
- lower 小写
  <h1> {{str|lower}} </h1>
- upper 大写
  <h1> {{str|upper}} </h1>
- join 传递参数(参数用引号引住)
  <h1> {{list|join:'#'}} </h1>
- default 默认值(如果一个变量没有被提供或值为false、空,可以使用默认值)
  <h1> {{username|default:'游客'}} </h1>
- date 根据给定格式转换日期为字符串
  <h1> {{dateValue|date:'y-m-d'}} </h1>
  • 标签inlcude
- 作用
  加载模板并以标签内的参数渲染
- 格式
  {% include '模板目录' 参数1 参数2 %}
- 例如:
  # 不传递参数
  {% include "content.html" %}
  # 传递参数scoreList
  {% include "content.html" with scores=scoreList  %}

由零合一,先完成小细节,最后使用include一起包含进去!

  • 标签url
- 作用
  反向解析
- 格式
  {% url 'namespace:name' p1 p2 %}

备注: 具体看下面详细说明。

  • 标签block、extends
- 作用
  用于模板的继承

备注: 具体看下面详细说明。

  • 标签autoescape
- 作用
  用于HTML转义

备注: 具体看下面详细说明。

  • 标签csrf_token
- 作用
  用于跨域请求伪造保护
- 格式
  {% csrf_token %}

备注: 具体看下面详细说明。

三、反向解析

- 反向解析语法
  {% url 'namespace:name' p1 p2 %}

- 项目的urls.py文件中
  url(r'^meituan/', include('app.urls', namespace='app') )

- 应用的urls.py文件中
  # 路由(带参数)  
  url(r'^goods/(\d+)/$',views.goods, name='goods'),

  # 视图函数(带参数,和url与之对应)
  def goods(request, page):
    return HttpResponse('商品列表: 第%s页' % page)
  

- 模板(带有参数的)
  <a href="{% url 'app:goods' 3 %}"> 商品列表 </a>
  <a href="{% url 'app:students' student.id %}">{{ student.s_name }}</a>

备注:
  name属性,即是给对对应的url添加一个名字;
  但是使用 name 也存在一定的问题 ,比如在同一个项目中的不同的app中 name 可能会重名;
  Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回;
  当不小心定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间;
  namespace命名空间;

反向解析场景: 正常情况下页面中设置的商品页链接地址都是goods/,而在服务器中路由如果发生一些细微的改变时,那么在页面中所有关于商品页链接地址都需要修改。为此可以使用反向解析解决此问题。

四、模板继承

  • 作用
模板继承可以减少页面内容的重复定义,实现页面的复用。
  • block标签
- 作用
  在父木模板中预留区域,子模板去填充
- 语法
  {% block 标签名 %}
  {% endblock 标签名 %}  
  • extends标签
- 作用
  继承模板,需要写在模板文件的第一行
- 语法
  {% extends '父模板路径' %}
  • 示例(定义父模板)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  {% block title %}
  {% endblock title %}
  <style>
      #header,#footer{
          height: 300px;
          background: red;
          line-height: 300px;
          color: white;
          text-align: center;
          font-size: 30px;
      }
      #footer{
          background: blue;
      }
  </style>
  {% block style %}
  {% endblock style %}
</head>

<body>
  <!--父模板(很多页面中,头部和尾部都是一致的)-->
  <div id="header">header</div>

  <!--主体内容不同,需要各部分进行填充-->
  <div id="content">
      <!--主体内容不确定,就直接这样写即可-->
      {% block content %}
      {% endblock content %}

      <br>
      <br>
      {% block test %}
      {% endblock test %}
  </div>

  <div id="footer">footer</div>
</body>

</html>
  • 示例(定义子模板1)
{% extends 'meituan/base.html' %}

{% block content %}
  <h1> 首页 --- 主体内容 </h1>
  <a href="{% url 'meituan:about' %}">关于我们</a>
{% endblock content %}
  • 示例(定义子模板2)
{% extends 'meituan/base.html' %}

{% block title %}
  <title>关于我们</title>
{% endblock title %}

{% block style %}
<style>
  h2{
      background: black;
      color: white;
  }
</style>
{% endblock style %}

{% block content %}
  <h1> about关于我们 </h1>
{% endblock content %}

<!--继承,可以填充,也可以不填充-->
{% block test %}
  <h2>我住隔壁,我姓王,你有事情我帮忙。</h2>
{% endblock test %}

五、HTML转义

  • 问题
<!--views.py-->
return render(request,'meituan/test2.html',{'code': '<h1>今天是周一.</h1>'})

<!--HTML转义-->
{{code}}

<!--问题-->
将接受到的code当前普通字符串渲染
  • 转义
将接受到字符串当成HTML代码渲染
<!--方式1-->
{{code|safe}}

<!--方式2-->
<!--关闭自动转义-->
{% autoescape off %}
  {{code}}
{% endautoescape %}

六、CSRF

- 跨域请求伪造
    某些恶意网站包含链接、表单、按钮、JS,利用用户登录在浏览器中认证,从而攻击服务
- 放置CSRF
    在settings.py文件中MIDDLEWARE添加'django.middleware.csrf.CsrfViewMiddleware'
    在form表单中添加 '{% csrf_token %}'
- 例如
<form action="{% url 'app:login' %}" method="post">
    {% csrf_token %}
    <input type="text" placeholder="输入验证码" name="text"> <br>
    <input type="submit" value="验证">
</form>

在没有放置CSRF时,会报错一下错误Forbidden (403) CSRF verification failed. Request aborted. More information is available with DEBUG=True.。

七、验证码

  • 作用
- 在用户注册、登录页面的使用使用,为了防止暴力请求,减轻服务器的压力
- 防止CSRF的一种方式

request.session.get["k1"],如果不存在则会报错,为了防止出错可以request.session.get('k1',none)

  • 示例(视图之生成验证码)
# 验证码
def verifycode(request):
    # 导入绘图模块
    from PIL import Image,ImageDraw,ImageFont
    # 导入随机函数模块
    import random
    # 文件操作
    import io

    # 定义变量,用于图片的背景色、宽、高
    # random.randrange()返回指定递增基数集合中的一个随机数
    bgcolor = (random.randrange(20,100),random.randrange(20,100),random.randrange(20,100))
    width = 100
    heigh = 50

    # 创建图片
    image = Image.new('RGB',(width,heigh),bgcolor)

    # 创建画笔对象
    draw = ImageDraw.Draw(image)

    # 调用画笔的point函数,绘制噪点
    for i in range(0,100):
        xy = (random.randrange(0,width),random.randrange(0,heigh))
        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))]

    # 构建字体对象
    # font = ImageFont.truetype(path) # 指定路径加载字体
    # font = ImageFont.load_default() # 加载一个默认的字体
    # truetype(font=None, size=10, index=0, encoding="", layout_engine=None)
    font = ImageFont.truetype('fonts/Songti.ttc',40)
    # font = ImageFont.truetype('fonts/STXINGKA.ttf',40)

    #构建字体颜色
    fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))

    # 绘制4个字
    # def text(self, xy, text, fill=None, font=None, anchor=None, *args, **kwargs):
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4)

    # 释放画笔
    del draw

    # 存入session,用于验证
    request.session['verify'] = rand_str

    # 文件操作
    buff = io.BytesIO()
    # 将图片保存在内存中,文件类型png
    image.save(buff,'png')

    # 将内存中图片数据返回给客户端,MIME类型为图片类型
    # 直接是返回验证码图片
    return HttpResponse(buff.getvalue(),'image/png')

PIL(Python Imaging Library)是Python一个强大方便的图像处理库,名气也比较大,不过只支持到Python 2.7。Pillow是PIL的一个派生分支,但如今已经发展成为比PIL本身更具活力的图像处理库。目前最新版本是3.0.0。
ython 3.x 安装Pillow: pip install Pillow

  • 示例(视图之登录)
# 登录操作
def verifycodefile(request):
    # 获取到session的flag标志值
    flag = request.session.get("flag", True)
    str = ''
    if flag == False:
        str = "请重新输入"

    # 清空session
    request.session.clear()

    return render(request, 'meituan/verifycodefile.html', {"flag": str})
  • 示例(视图之登录验证码验证)
# 登录验证
def verifycodecheck(request):
    # 输入的验证码
    # upper()转为大写
    code1 = request.POST.get('verifycode').upper()
    # session验证码
    code2 = request.session['verify'].upper()
    
    if code1 == code2:  # 验证成功
        return render(request,'meituan/success.html')
    else:   # 重新登录操作
        request.session["flag"] = False
        return redirect('/meituan/verifycodefile/')
  • 示例(url管理器)
urlpatterns=[
    url(r'^verifycode/$',views.verifycode), # 验证码测试
    url(r'^verifycodecheck/$',views.verifycodecheck),    # 验证操作
    url(r'^verifycodefile/$',views.verifycodefile),  # 带验证码登录
]
  • 示例(模板)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录 | 验证码测试</title>
</head>
<body>
    <!--验证码-->
    <!--默认什么都添加,就是直接显示-->


    <!--添加登录功能验证-->
    <form action="/meituan/verifycodecheck/" method="post">
        {%csrf_token%}
        <input type="text" name="verifycode" />
        <img src="/meituan/verifycode/" /> <br>
        <input type="submit" value="验证" /> <br>
        <span>{{flag}}</span>
    </form>

</body>
</html>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 一、模板概述 模板组成HTML代码动态插入的代码(挖坑、填坑逻辑控制代码) 作用快速生成HTML页面 优点模板的设...
    EndEvent阅读 1,605评论 0 3
  • 一、模板概述 模板组成 作用 优点 模板处理 二、定义模板 变量 标签 单行注释 标签if 标签for 标签com...
    王梓懿_1fbc阅读 395评论 0 0
  • 模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚...
    riverstation阅读 2,061评论 0 8
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 在上一个章节,我们已经创建了一个基础的Blog程序。现在我们将使用一些Dajngo高级功能,去实现一个完整的blo...
    金金刚狼阅读 3,575评论 1 12