Django 模板

Django 2019-06-22

一、模板概述

在Django框架中,模板是可以帮助开发者快速生成呈现给用户页面的工具,模板的设计方式实现了我们MTV中V和T的解耦。

1.模板组成

HTML代码
动态插入的代码(挖坑、填坑逻辑控制代码)

2.作用

快速生成HTML页面

3.优点

模板的设计实现了业务逻辑与现实内容的分离
视图可以使用任何模板

4.模板处理

加载
渲染

二、定义模板

1.变量

- 视图传递给模板的数据
- 变量遵守标识符规则
- 语法
  {{ var }}
- 注意
  变量若不存在,则插入空的字符串
- 点语法
 字典查询、属性或方法、数字索引 

2.标签

- 语法
  {% tag %}
- 作用
  在输出中创建文本
  控制逻辑和循环

3.单行注释

{# 注释内容 #}

4.标签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%}

5.标签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>

6.标签comment

- 作用
  多行注释
- 例如
  {% comment %}
      <p>姓名: {{student.sname}}</p>
      <p>性别: {{student.ssex}}</p>
      <p>年龄: {{student.sage}}</p>
      <p>座右铭: {{student.sbrief}} </p>
  {% endcomment %}

7.标签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 %}

8.过滤器

- 作用
  在变量被显示前修改它
- 语法
  {{ 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>

9.标签inlcude

- 作用
  加载模板并以标签内的参数渲染
- 格式
  {% include '模板目录' 参数1 参数2 %}
- 例如:
  # 不传递参数
  {% include "content.html" %}
  # 传递参数scoreList
  {% include "content.html" with scores=scoreList  %}

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

10.标签url

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

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

11.标签block、extends

- 作用
  用于模板的继承

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

12.标签autoescape

- 作用
  用于HTML转义

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

13.标签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/,而在服务器中路由如果发生一些细微的改变时,那么在页面中所有关于商品页链接地址都需要修改。为此可以使用反向解析解决此问题。

四、模板继承

1.作用

模板继承可以减少页面内容的重复定义,实现页面的复用。

2.block标签

- 作用
  在父木模板中预留区域,子模板去填充
- 语法
  {% block 标签名 %}
  {% endblock 标签名 %}  

3.extends标签

- 作用
  继承模板,需要写在模板文件的第一行
- 语法
  {% extends '父模板路径' %}

4.示例(定义父模板)

<!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>

5.示例(定义子模板1)

{% extends 'meituan/base.html' %}

{% block content %}
  <h1> 首页 --- 主体内容 </h1>
  <a href="{% url 'meituan:about' %}">关于我们</a>
{% endblock content %}

6.示例(定义子模板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转义

1.问题

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

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

<!--问题-->
将接受到的code当前普通字符串渲染

2.转义

将接受到字符串当成HTML代码渲染
<!--方式1-->
{{code|safe}}

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

六、CSRF

浏览器会对跨域请求作出限制。浏览器之所以要对跨域请求作出限制,是出于安全方面的考虑,因为跨域请求有可能被不法分子利用来发动CSRF攻击。
CSRF(Cross-site request forgery),中文名称:跨站请求伪造。

例如,A网站是真实受信任的网站,B网站是高危的网站。
用户登陆了受信任的A网站【本地会存储A网站相关的Cookie,并且浏览器也维护这一个Session会话】。

危险网站B,此时用上面存储的用户信息,模拟向A网站发起请求,并对A网站进行操作(跨域请求)。

而在A网站的角度来看是并不知道请求是由B网站发出来的(Session和Cookie均为A网站的),这时便成功发动一次CSRF 攻击。

【攻击者盗用了你的身份,以你的名义发送请求。】

解决方式

 - 放置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>

备注1: 在没有放置CSRF时,会报错一下错误Forbidden (403) CSRF verification failed. Request aborted.More information is available with DEBUG=True.
备注2: ajax 发起post请求时,需要csrf_token,其实scirpt标签中也适合于模板语法操作的!


本文由 zyz 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

楼主残忍的关闭了评论