作者 | 单雨
责编 | 屠敏
出品 | CSDN(ID:CSDNnews)

模板继承

简介

模板继承允许你建立一个基本的"骨架"模板, 它包含了网站中所有常见的元素,并定义了可以被子模板覆盖的 块(blocks) 。示例:

假如父模板base.html如下:

<!DOCTYPE html>
<html lang="en">
<head><link rel="stylesheet" href="style.css"><title>{% block title %}My amazing site{% endblock %}</title>
</head><body><div id="sidebar">{% block sidebar %}<ul><li><a href="/">Home</a></li><li><a href="/blog/">Blog</a></li></ul>{% endblock %}</div><div id="content">{% block content %}{% endblock %}</div>
</body>
</html>

它定义了一个简单的 HTML 骨架文档, 假设这是一个简单的两列页面。子模板的工作就是填充空的 块(block) 中的内容。

在这个例子中, block 标签定义了三个可以被子模板填充的块。block标签告诉了模板系统哪些地方可能被子模板覆盖。例如,子模板可能如下:

{% extends "base.html" %}{% block title %}My amazing blog{% endblock %}{% block content %}
{% for entry in blog_entries %}<h2>{{ entry.title }}</h2><p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

extends 标签告诉模板系统这个模板继承了另外的模板。当模板系统对此模板进行运算时, 首先会寻找他的父模板 ——在这里是"base.html"。

在这一点上, 模板引擎会在 base.html 中发现三个 block 标签, 并且使用子模板的内容替换掉这些块。根据变量blog_entries 的值, 输出可能看起来像这样:

<!DOCTYPE html>
<html lang="en">
<head><link rel="stylesheet" href="style.css"><title>My amazing blog</title>
</head><body><div id="sidebar"><ul><li><a href="/">Home</a></li><li><a href="/blog/">Blog</a></li></ul></div><div id="content"><h2>Entry one</h2><p>This is my first entry.</p><h2>Entry two</h2><p>This is my second entry.</p></div>
</body>
</html>

注意:因为子模板没有定义 sidebar 块, 那么父模板的内容就会被使用。通常来说, 父模板 {% block %} 中的内容会被作为备用的内容,在子模板没有覆盖时就会被使用。

多重继承

模板继承可以是多重继承,多重继承常见的模式是:

  • 创建一个 base.html 模板把控网站的整体风格。

  • 为网站的每个子分类创建一个 baseSECTIONNAME.html模板. 比如, basenews.html, base_sports.html。 这些模板都继承 base.html 模板。这些模板中包含特定的设计/风格。

  • 为每一种类型的页面创建一个模板, 比如 news article 或blog 内容。这些模板扩展上一级模板的相应分类。

上述的关系可以用下图表示:

这样就能最大限度的重用模板代码,比如在所有页面通用的导航栏。

模板继承注意事项

  • {% extends %}必须位于模板的最开始, 如果在其他的部分声明, 则不生效。

  • 在基础模板尽可能多的使用{%block%} ,子模板不需要定义所有父模板中的块, 所以你可以在若干的块中填充默认值, 然后定义之后需要自定义的块, 有更多的可用块总是更好的。

  • 如果发现自己在许多模板中有重复内容的了, 这可能需要移动这些内容到父模板的 {% block %} 中。

  • 如果需要得到父模板块中的内容, 可以用{{ block.super }} 变量。使用 {{ block.super }} 插入的数据不会被自动转义 ,因为它已经被转义了。如果需要转义, 可以在父模板中转义。

  • 使用模板标签在{% block %}块外部创建的变量不能在块内使用。例如,这个模板不渲染任何东西:

  {% trans "Title" as title %}{% block content %}{{ title }}{% endblock %}

  • 为了具有更好的可读性,也可以给{% endblock %}块标签定义一个名字。例如:

  {% block content %}...{% endblock content %}

在一个较长的模板中, 这个方法可以让你知道是哪一个{% block %} 标签定义结束了。

  • 不能在同一模板中定义多个具有相同名称的块标签。存在这个限制是因为{%block%}标签是"双向"定义的。也就是说, 它不仅指定了子模板要填充父模板的哪个块, 也说明了父模板要引用哪些子模板块的内容。所以在子模板中有多个同名的{%block%}标签时, 父模板就不知道到底要引用子模板中哪个块的内容了。

自动HTML转义

从模板直接生成HTML存在XSS风险

从模板生成HTML时, 总是有一种风险, 即一个变量将会影响生成的HTML字符。考虑这个模板片段:

Hello, {{ name }}

看起来可能没有什么风险,但是如果用户输入的名字为一个HTML代码:

<script>alert('hello')</script>

当{{name}}为这个值时,模板将呈现为:

Hello, <script>alert('hello')</script>

这将使浏览器弹出一个弹出一个JavaScript警告。同样的,考虑另外一种情况:

如果名字中包含一个 '<' 符号:

<b>username

对应的模板将为:

Hello, <b>username

这意味着在此之后的文字将呈现为粗体。

由此带来一个风险:

用户提交的数据是不可靠的且不应被直接插入到您的网页, 因为恶意用户可以使用这种潜在的漏洞做危害网站的事情。这种类型的安全漏洞被称为 Cross Site Scripting (跨站脚本) (XSS) 攻击。

使用转义避免XSS风险

(1)使用escape标签

确保让不受信任的变量经过了 escape 过滤器 , 将危险的HTML字符替换为无害的HTML转义字符。但是这常常被忽略。

(2)使用自动转义

在Django中, 默认每个模板会自动转义输出的每一个变量标签。具体来说, 这五个字符会被转义:

  • < 被替换为 &lt;

  • > 被替换为 &gt;

  • ' (单引号) 被替换为 '

  • " (双引号) 被替换为 &quot;

  • & 被替换为 &amp;

这种行为是默认的。如果使用的是Django的模板系统, 自然拥有这种保护。

关闭自动转义

可以在站点,模板和变量三个层级关闭自动转义。

(1)对单个变量

要为一个单独的变量禁用自动转义, 使用 safe 过滤器(https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#std:templatefilter-safe):

This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}

如果变量中包含“\”字符,输出也是“\”。

(2)对于模板文本块

要在模板中控制自动转义, 可以在整个模板 (或者模板的特定区域) 使用 autoescape 标签, 如:

{% autoescape off %}Hello {{ name }}
{% endautoescape %}}}

autoescape 标签接受 on 或 off 作为参数。如果需要在某个区域禁用自动转义,可以这样使用:

{% autoescape off %}This will not be auto-escaped: {{ data }}.Nor this: {{ other_data }}{% autoescape on %}Auto-escaping applies again: {{ name }}{% endautoescape %}
{% endautoescape %}

(3)自动转义的继承特性

如果使用自动转义的模板文本块中使用{%block%}包含了子模板,那么子模板中也将使用自动转义,如果基模板中关闭了自动转义,那么子模板中也将关闭自动转义:

base.html:

{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}

child.html:

{% extends "base.html" %}
{% block title %}This &amp; that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}

因为基模板中关闭了自动转义,子模板中也将关闭自动转义,所以在HTML渲染时,greeting 变量被输出为 <b>Hello!</b>:

<h1>This &amp; that</h1>
<b>Hello!</b>

(4)注意事项 

模板的开发者并不需要对自动转义太过关注. 这是编写Python的开发者 (写视图和写自定义模板标签的人) 需要考虑的事. 所以, 你只需要做和模板有关的活。如果你不确定模板在何时会进行自动转义(或不进行), 那么就向所有需要转义的变量添加 escape 过滤器. 当自动转义被打开, escape 过滤器不会再次转义 -- escape 过滤器不会影响自动转义的变量。

(5)字符串和自动转义

过滤器的参数可以是字符串,例如:

{{ data|default:"This is a string literal." }}

作为过滤器参数的字符串都不会自动转义, django认为它们已经经过safe 过滤。这么做的原因是模板的开发者可以控制字符的输出, 所以他们应该确保正确的使用转义后的HTML字面值。

这意味着你应该这么写:

{{ data|default:"3 &lt; 2" }}

而不是:

{{ data|default:"3 < 2" }} 

模板中的对象方法调用

大多数附加到对象上的方法都可以在模板中调用,这使得模板可以从视图中传递过来的上下文变量中获取对象属性之外的值。

例如, Django ORM 提供了 "entry_set" 语法寻找一个与外键所关联的对象的集合。因此, 如果有一个叫 "comment" 的模型有外键指向了模型 "task",你可以通过给定一个实际的 task模板变量, 像这样循环输出与它相关联所有的 comment对象:

{% for comment in task.comment_set.all %}{{ comment }}
{% endfor %}

如果你在一个模型中显示定义了一个方法,你也可以在对应的模板变量中引用它:

模型

class Task(models.Model):def foo(self):return "bar"

模板调用

{{ task.foo }}

注意:由于Django有意限制了模板中语言逻辑的处理,所以不能在模板内调用对象方法时向其传递参数。数据应当在视图中计算完成后,再传递给模板。

作者简介:单雨,90后工科男,伪文艺青年。目前就读于北京理工大学宇航系,喜欢研究AI,网络爬虫,微信小程序以及机器人,痴迷于Coding,睡前必撸码。

【END】

四大项目,让你成为Python全栈工程师?

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

 热 文 推 荐 

点击阅读原文,即刻阅读《程序员大本营》最新期刊。
你点的每个“在看”,我都认真当成了喜欢

轻松搞定 Django 模板语言进阶!相关推荐

  1. 报表控件ActiveReports可以轻松搞定报表模板设计,赶紧get起来

    ActiveReports 是一款专注于 .NET 和 .NET Core 平台的报表控件.通过拖拽式报表设计器,可以快速地设计 Excel表格.Word文档.图表.数据过滤.数据钻取.精准套打等类型 ...

  2. 9月20日云栖精选夜读 | 如何轻松搞定数据科学面试:Python&R语言篇

    对于数据科学家来说,工作的一大部分都需要在交互式编程环境中对数据进行处理.分析和可视化. 在过去几年,R语言和Python成了进行数据科学中最炙手可热的两种语言.这两种语言各有优缺点,掌握这两种语言大 ...

  3. 好的设计善于利用PSD模板,轻松搞定促销海报!

    在设计促销海报之前,首先要明白你表达的中心思想是什么?需要突出的主题是什么?那么作图之前首先就要构思好,在这张海报里哪些是需要突出的部分,需要做得够大.够漂亮,这样才能有力传递促销信息. 好的设计善于 ...

  4. pythonr语言三种基本结构_如何轻松搞定数据科学面试:Python&R语言篇

    作者: Carson Forter 编译: Mika本文为 CDA 数据分析师原创作品,转载需授权 对于数据科学家来说,工作的一大部分都需要在交互式编程环境中对数据进行处理.分析和可视化. 在过去几年 ...

  5. 基于 CODING 轻松搞定持续集成

    点击观看视频教程 带你一步一步搞定 CODING 持续集成 持续集成加速软件交付 持续集成这个概念是由 Grady Booch 在 1991 年首次提出,随后成为了 DevOps 的核心实践之一.持续 ...

  6. coding制品库持续集成php项目,基于 CODING 轻松搞定持续集成

    点击观看视频教程 带你一步一步搞定 CODING 持续集成 持续集成加速软件交付 持续集成这个概念是由 Grady Booch 在 1991 年首次提出,随后成为了 DevOps 的核心实践之一.持续 ...

  7. html百度首页制作视频,韩顺平 轻松搞定网页设计 html+css+js

    韩顺平老师的教程影响着一代又一代的学子们,他的视频教程确实做的很经典,不论是java.php还是网页设计,都有出彩的地方.这里,小编给大家分享韩顺平老师的轻松搞定网页设计教程,绝对完整,全部存于百度网 ...

  8. 【微服务】之六:轻松搞定SpringCloud微服务-API网关zuul

    通过前面几篇文章的介绍,我们可以轻松搭建起来微服务体系中比较重要的几个基础构建服务.那么,在本篇博文中,我们重点讲解一下,如何将所有微服务的API同意对外暴露,这个就设计API网关的概念. 本系列教程 ...

  9. Django模板语言(译)

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

最新文章

  1. Matlab与线性代数 -- 矩阵的右除
  2. 洛谷P4199 万径人踪灭(manacher+FFT)
  3. 常见人名大全_生辰八字起名取名:2020年属鼠的女孩起名字大全
  4. uva 1610——Party Games
  5. 前端学习(2941):vue的生命周期
  6. 做图表统计你需要掌握SQL Server 行转列和列转行
  7. linux nginx mysql php 5.5.,编译安装Linux + Nginx1.10 + Mysql5.5 + PHP5.6
  8. 如何在Mac视频中删除音频呢?
  9. 教你如何轻松玩转自媒体淘客,赚大钱!
  10. R语言入门-常用的向量运算
  11. 纪念下大二参加的全国大学生智能汽车竞赛
  12. android系统关机广播,Android开机广播和关机广播
  13. 官方:“四个放宽”、“三个加强”安置退役军人
  14. Jeff Dean长文展望:机器学习领域的五大潜力趋势
  15. 为什么我在领英上搜到的客户都是显示领英会员(Linkedin Member)?
  16. MySQL建员工表案例
  17. 【考研真题】四川大学2019初试真题 已更新在GitHub
  18. linux运维培训后面试,Linux运维岗位面试中常见的面试问题汇总
  19. 从零开始开发3D跑酷游戏教程-洪青霞-专题视频课程
  20. CAD图纸转换为PDF的方法——Speedpdf免费在线CAD转PDF

热门文章

  1. 跟闺密逛街 越逛越穷
  2. ASP.NET页生命周期介绍:阶段,事件及其他
  3. 《TensorFlow 2.0深度学习算法实战教材》学习笔记(七、Kears高层接口)
  4. Spark逻辑图的执行
  5. [C++] printf 打印 string 类型
  6. php数组的奇数_PHP - 查找数组元素是奇数还是偶数
  7. 记录——《C Primer Plus (第五版)》第八章编程练习第五题
  8. 《推荐系统笔记(十)》CTR预估以及一般算法介绍(GBDT+LR)
  9. 剑指Offer字符串转换成整数
  10. 泛型的应用-vue3之ref