模板层 Template

每一个 Web 框架都需要一种很便利的方法用于动态生成 HTML 页面。 最常见的做法是使用模板。

模板包含所需 HTML 页面的静态部分,以及一些特殊的模版语法,用于将动态内容插入静态部分。

说白了,模板层就是如何往 HTML 文件中填入动态内容的系统。

Django 可以配置一个或多个模板引擎(语言),也可以不用引擎。

Django 自带一个称为 DTL(Django Template Language )的模板语言,以及另外一种流行的 Jinja2 语言(需要提前安装,pip install Jinja2)。

Django 为加载和渲染模板定义了一套标准的 API,与具体的后台无关。加载指的是,根据给定的模版名称找到模板然后预处理,通常会将它编译好放在内存中。渲染则表示,使用 Context 数据对模板插值并返回生成的字符串。

DTL 作为 Django 原生的模板系统,一直到 Django1.8,都是唯一的内置模板系统。如果没有特别重要的理由,需要选择另外一种模板系统的话,建议坚持使用 DTL。

Django 很多内部组件都使用了 DTL,例如 django.contrib.admin,如果你不想让它们罢工,或者花费大力气进行修改,不要放弃 DTL。

一、 配置引擎

模板引擎通过 settings 中的 TEMPLATES 设置来配置。这是一个列表,与引擎一一对应,每个元素都是一个引擎配置字典。由 startproject 命令生成的settings.py 会自定定义如下的值:

TEMPLATES = [
  {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [],
    'APP_DIRS': True,
    'OPTIONS': {
      # ... some options here ...
    },
  },
]

BACKEND:后端。

内置的后端有 django.template.backends.django.DjangoTemplates 和django.template.backends.jinja2.Jinja2。

OPTIONS 中包含了具体的后端设置。

由于绝大多数引擎都是从文件加载模板的,所以每种模板引擎都包含两项通用设置:

  1.DIRS:定义了一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件。

  2.APP_DIRS:告诉模板引擎是否应该进入每个已安装的应用中查找模板。通常请将该选项保持为 True。

每种模板引擎后端都定义了一个惯用的名称作为应用内部存放模板的子目录名称。(例如 Django 为它自己的模板引擎指定的是 ‘templates’,为 jinja2 指定的名字是‘jinja2’)。尤其是,django 允许你有多个模板引擎后端实例,且每个实例有不同的配置选项。 在这种情况下你必须为每个配置指定一个唯一的 NAME .

DTL 引擎的 OPTIONS 配置项中接受以下参数:

  1.'autoescape':一个布尔值,用于控制是否启用 HTML 自动转义功能。默认为 True。

  2.context_processors: 以"."为分隔符的 Python 调用路径的列表。默认是个空列表。

  3.'debug':打开/关闭模板调试模式的布尔值。默认和 setting 中的 DEBUG 有相同的值。

  4.'loaders':模板加载器类的虚拟 Python 路径列表。默认值取决于 DIRS 和APP_DIRS 的值。

  5.string_if_invalid:非法变量时输出的字符串。默认为空字符串。

  6.file_charset:用于读取磁盘上的模板文件的字符集编码。默认为 FILE_CHARSET的值。

  7.'libraries':用于注册模板引擎。 这可以用于添加新的库或为现有库添加备用标签。

  8.'builtins':以圆点分隔的 Python 路径的列表。

二、 简单的用法

django.template.loader 中定义了两个函数以加载模板。

get_template(template_name,using = None)

该函数使用给定的名称查找和加载模板,并返回一个 Template 对象。

模板的查找和加载机制取决于每种后端引擎和配置,如果想使用指定的模板引擎进行查找,请将模板引擎的 NAME 赋给 get_template 的 using 参数。

select_template(template_name_list,using = None)

和 get_template()相似, 只不过它使用包含模板名称的列表作为参数。

由 select_template()和 get_template()返回的 Template 对象都必须提供一个 render()方法,如下所示:

Template.render(context=None, request=None)

通过给定的 context 对该模板进行渲染。

如果提供了 context,那么它必须是一个 dict 对象。如果要提供 request 参数 ,必须使用 HttpRequest 对象。

针对下面的 TEMPLATES 配置,对模版文件的搜索顺序和路径如下:

TEMPLATES = [
  {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [
    '/home/html/example.com',
    '/home/html/default', ], }, {
    'BACKEND': 'django.template.backends.jinja2.Jinja2',
    'DIRS': [
      '/home/html/jinja2', 
    ],
  },
]

如果你调用函数 get_template('story_detail.html'), Django 将按以下顺序查找story_detail.html:

/home/html/example.com/story_detail.html('django'引擎)

/home/html/default/story_detail.html('django'引擎)

/home/html/jinja2/story_detail.html('jinja2'引擎)

如果你调用函数 select_template(['story_253_detail.html','story_detail.html']),Django按以下顺序查找:

/home/html/example.com/story_253_detail.html('django'引擎)

/home/html/default/story_253_detail.html('django'引擎)

/home/html/jinja2/story_253_detail.html('jinja2'引擎)

/home/html/example.com/story_detail.html('django'引擎)

/home/html/default/story_detail.html('django'引擎)

/home/html/jinja2/story_detail.html('jinja2'引擎)

注意:Django 查找到任何一个匹配的模板后便停止搜寻,所以这是个类似 url 搜索的短路操作!

强调:前面我们介绍过,建议在每个 APP 的的模版子目录下都建立一个子目录来唯一对应这个 APP。这样做可以增强你的 APP 的可用性。 将所有的模版文件放在根模版目录下会引发混淆。

要在一个子目录内加载模板,像下面这样:

get_template('news/story_detail.html')

如果结合上面例子中的 TEMPLATES 配置,这将会尝试按顺序查找并加载下列模板︰

/home/html/example.com/news/story_detail.html('django'引擎)

/home/html/default/news/story_detail.html('django'引擎)

/home/html/jinja2/news/story_detail.html('jinja2'引擎)

另外,为了减少加载模板、渲染模板等重复工作,django 提供了处理这些工作的快捷函数。

render_to_string(template_name, context=None, request=None,using=None)[source]

render_to_string()会像 get_template()一样加载模板并立即调用 render()方法。 它需要以下参数。

  1.TEMPLATE_NAME:要加载的模板的名称或列表。

  2.context:要用作模板的上下文进行渲染的数据字典,也就是你要插入的动态数据字典。

  3.request:可选的 HttpRequest 对象。

  4.using:指定使用的模板引擎 NAME。 搜索模板将仅限于该引擎。

用法示例:

from django.template.loader import render_to_string

rendered = render_to_string('my_template.html', {'foo': 'bar'})

三、基本语法

Django 模板语言(DTL)的语法包括四种结构。

1. 变量

变量的值来自 context 中的数据字典, 类似于字典对象的 keys 到 values 的映射关系。

变量是被}}和{{括起来的部分,例如:

My first name is {{ first_name }}. My last name is {{ last_name }}.

当模版引擎遇到一个变量,它将从上下文 context 中获取这个变量的值,然后用值替换掉它本身。假如有一个上下文{'first_name': 'John', 'last_name': 'Doe'},模板渲染后的真实值为:

My first name is John. My last name is Doe.

变量的命名包括任何字母数字以及下划线("_")的组合。点(".")也有可能会在变量名中出现,不过它有特殊的含义。最重要的是,变量名称中不能有空格或标点符号。

当模版系统遇到点("."),它将以这样的顺序查询这个圆点具体代表的功能:

  1.字典查询(Dictionary lookup)

  2.属性或方法查询(Attribute or method lookup)

  3.数字索引查询(Numeric index lookup)

如果你使用的变量不存在,模版系统将插入 string_if_invalid 选项的值,默认设置为''(空字符串)。

2. 标签

模版语言中的标签类似 Python 中的函数,功能多样,使用灵活。可以输出内容、控制结构,甚至可以访问其他的模板标签。

标签是由%}和{%来定义的,例如:

{% csrf_token %} # csrf 令牌标签

大部分标签都接受参数:

{% cycle 'odd' 'even' %} # 循环使用'odd'和'even'

部分标签需要使用起始和闭合标签,典型代表为 for 循环标签和 if 判断标签:

{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}

Django 自带了大约 24 个内置的模版标签。下面是一些常用的标签:

2.1. for 循环标签

循环对象中每个元素。需要结束标签{% endfor %} 。例如,显示 athlete_list中提供的运动员列表:

<ul>
{% for athlete in athlete_list %}
  <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

2.2. if,elif 和 else 标签

计算一个表达式,并且当表达式的值是“True”时,显示块中的内容。需要{%endif %}结束标签。整体逻辑非常类似 Python 的 if、elif 和 else,如下所示。:

{% if athlete_list  %}
  Number of athletes:  {{ athlete_list|length  }}
{% elif athlete_in_locker_room_list  %}
  Athletes should be out of the locker room soon!
{% else  %}
  No athletes.
{% endif  %}

在上面的例子中,如果 athlete_list 不是空的,运动员的数量将显示为{{ athlete_list|length }}。否则,如果 athlete_in_locker_room_list 不为空,将显示“Athletes should be out…”。如果两个列表都是空的,将显示“No athletes.” 。

还可以在 if 标签中使用过滤器和多种运算符:

{% if athlete_list|length > 1 %}
  Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
  Athlete: {{ athlete_list.0.name }}
{% endif %}

需要注意,大多数模版过滤器都返回字符串类型,所以使用过滤器做整数类型的比较通常是错误的,但 length 是一个例外。

2.3. block 和 extends 标签

继承和复写模版。类似 Python 的类继承和重写机制。

3. 过滤器

过滤器看起来是这样的:{{ name|lower }}。使用管道符号(|)来应用过滤器。该过滤器将文本转换成小写。

过滤器可以“链接”。一个过滤器的输出应用于下一个过滤器。例如:

{{ text|escape|linebreaks }}就是一个常用的过滤器链,它首先转移文本内容,然后把文本行转成<p>标签。

一些过滤器带有参数。 过滤器的参数看起来像是这样: {{ bio|truncatewords:30 }}。这将显示 bio 变量的前 30 个词。

过滤器参数包含空格的话,必须用引号包起来。例如,使用逗号和空格去连接一个列表中的元素,你需要使用{{ list|join:", " }}。

Django 提供了大约六十个内置的模版过滤器,很多时候你想要的功能,它都已经提供了,有需要的时候就去查一下吧。下面是一些常用的模版过滤器:

3.1. default

为 false 或者空变量提供默认值,像这样:

{{ value|default:"nothing" }}

3.2. length

返回值的长度。它对字符串和列表都起作用。

{{ value|length }}

如果 value 是['a', 'b', 'c', 'd'],那么输出 4。

3.3. filesizeformat

格式化为“人类可读”文件大小单位(即'13 KB',4.1 MB','102 bytes'等)。

{{ value|filesizeformat }}

如果 value 是 123456789,输出将会是 117.7MB。

4. 注释

模版语言的注释看起来像这样:

{# this won't be rendered #} # 单行注释

{% comment %}标签提供多行注释功能。

附:

Django 内置标签总览

可以查询下表来总览 Django 的内置标签:

标签说明
autoescape自动转义开关
block块引用
comment注释
csrf_tokenCSRF 令牌
cycle循环对象的值
debug调试模式
extends继承模版
filter过滤功能
firstof输出第一个不为 False 的参数
for循环对象
for … empty带 empty 说明的循环
if条件判断
ifequal如果等于
ifnotequal如果不等于
ifchanged如果有变化,则..
include导入子模版的内容
load加载标签和过滤器
lorem生成无用的废话
now当前时间
regroup根据对象重组集合
resetcycle重置循环
spaceless去除空白
templatetag转义模版标签符号
url获取 url 字符串
verbatim禁用模版引擎
widthratio宽度比例
with上下文变量管理器

 

Django 内置过滤器总览

可以查询下表来总览 Django 的内置过滤器:

过滤器  说明
add加法
addslashes添加斜杠
capfirst首字母大写
center文本居中
cut切除字符
date日期格式化
default设置默认值
default_if_none为 None 设置默认值
dictsort字典排序
dictsortreversed字典反向排序
divisibleby整除判断
escape转义
escapejs转义 js 代码
filesizeformat文件尺寸人性化显示
first第一个元素
floatformat浮点数格式化
force_escape强制立刻转义
get_digit获取数字
iriencode转换 IRI
join字符列表链接
last最后一个
length长度
length_is长度等于
linebreaks行转换
linebreaksbr行转换
linenumbers行号
ljust左对齐
lower小写
make_list分割成字符列表
phone2numeric电话号码
pluralize复数形式
pprint调试
random随机获取
rjust右对齐
safe安全确认
safeseq列表安全确认
slice切片
slugify转换成 ASCII
stringformat字符串格式化
striptags去除 HTML 中的标签
time时间格式化
timesince从何时开始
timeuntil到何时多久
title所有单词首字母大写
truncatechars截断字符
truncatechars_html截断字符
truncatewords截断单词
truncatewords_html截断单词
unordered_list无序列表
upper大写
urlencode转义 url
urlizeurl 转成可点击的链接
urlizetruncurlize 的截断方式
wordcount单词计数
wordwrap单词包裹
yesno将 True,False 和 None,映射成字符串‘yes’,‘no’,‘maybe’

 

 

四、模板继承

Django 模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承允许你创建一个包含基本“骨架”的父模版,它包含站点中的共有元素,并且可以定义能够被子模版覆盖的 blocks。

通过下面这个例子,理解模版继承的概念:

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

这个模版,通常被命名为 base.html,它定义了一个可以用于两列排版页面的简单HTML 骨架。

“子模版”需要做的是先继承父模板 base.html,然后复写、填充,或者说实现其中的blocks。

block 是在子模版中可能会被覆盖掉的位置。在上面的例子中,block 标签定义了三个可以被子模版内容填充的 block,分别是 title、content 和 siderbar。

子模版可能看起来是这样的:

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

extends 标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个模版。当模版系统处理这个模版时,首先会去加载父模版,也就是“base.html”。

加载过程中,模版引擎将注意到 base.html 中的三个 block 标签,并用子模版中的内容来替换这些 block。 根据 blog_entries 的值,最终输出可能看起来是这样的:

<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,这种情况下,将使用父模版中的内容。父模版的{% block %}标签中的内容总是被用作默认内容。

下面是使用继承的一些相关说明

  1.如果在模版中使用{% extends %}标签,它必须是模版中的第一个标签,必须放在文件首行!

  2.在 base 模版中设置越多的{% block %}标签越好。子模版不必定义全部父模版中的 blocks,所以可以在大多数 blocks 中填充合理的默认内容,然后,只定义你需要的那一个。

  3.如果发现你自己在复制大量重复的模版内容,那意味着你应该把重复的内容移动到父模版中的一个{% block %}中。

  4.如果需要获取父模板中的 block 的内容,可以使用{{ block.super }}变量。如果想要在父 block 中新增内容而不是完全覆盖它,这将非常有用。

  5.在{% block %}之外创建的变量使用模板标签的 as 语法,不能在块内使用。

例如,下面的模板不会显示任何内容:

{% trans "Title" as title %}

{% block content %}{{ title }}{% endblock %}

1.为了更好的可读性,可以给{% endblock %}标签一个名字,

像这样:{% block content %} ... {%endblock content %}

在大型模版中,这有助于你清楚的看到哪一个{% block %}标签被关闭了。

2.最后,请注意不能在一个模版中定义多个相同名字的 block 标签

1.创建一个 base.html 模版,用来控制整个站点的主要视觉和体验。

2.为站点的每一个 app,创建一个 base_SECTIONNAME.html 模版。 例如base_user.html,base_goods.html。这些模版都继承 base.html,并且包含了各自特有的样式和设计。

3.为每一个页面类型,创建独立的模版。 这些模版继承对应 app 的模版。上面的方式可以使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单,例如 app 范围内的导航条。

 

 

五、CSRF

CSRF(Cross-site request forgery)跨站请求伪造,是一种常见的网络攻击手段。

Django 为我们提供了防范 CSRF 攻击的机制。

1、基本使用

默认情况下,使用 django-admin startproject xxx 命令创建工程时,CSRF 防御机制就已经开启了。如果没有开启,请在 MIDDLEWARE 设置中添加'django.middleware.csrf.CsrfViewMiddleware'。

对于 GET 请求,一般来说没有这个问题,CSRF 通常是针对 POST 方法的!

在含有 POST 表单的模板中,需要在其<form>表单元素内部添加 csrf_token 标签,如下所示:

 

<form action="" method="post">
  {% csrf_token %}
  ....
</form>

这样,当表单数据通过 POST 方法,发送到后台服务器的时候,除了正常的表单数据外,还会携带一个 CSRF 令牌随机字符串,用于进行 csrf 验证。如果表单中没有携带这个 csrf 令牌,会报错。

六、图片验证码

为了防止机器人频繁登录网站或者破坏分子恶意登录,很多用户登录和注册系统都提供了图形验证码功能。

在 Django 中实现图片验证码功能非常简单,有现成的第三方库可以使用,我们不必自己开发,这个库叫做 django-simple-captcha。

1、安装 captcha

执行命令:pip install django-simple-captcha

Django 自动帮我们安装了相关的依赖库 six、olefile 和 Pillow,其中的 Pillow 是大名鼎

鼎的绘图模块。

2、注册 captcha

在 settings 中,将‘captcha’注册到 app 列表里:

captcha 需要在数据库中建立自己的数据表,所以需要执行 migrate 命令生成数据表:

3、添加 url 路由

在根目录下的 urls.py 文件中增加 captcha 对应的网址:

urlpatterns = [
  ……..
  url(r'^captcha', include('captcha.urls')) # 增加这一行
]

4、修改 forms.py

如果上面都 OK 了,就可以直接在我们的 forms.py 文件中添加 CaptchaField 了。

from django import forms
from captcha.fields import CaptchaField
class UserForm(forms.Form):
  username = forms.CharField(label="用户名", max_length=128,widget=forms.TextInput(attrs={'class': 'form-control'}))
  password = forms.CharField(label="密码", max_length=256,widget=forms.PasswordInput(attrs={'class': 'form-control'}))
  captcha = CaptchaField(label='验证码')

注意需要提前导入 from captcha.fields import CaptchaField,然后就像写普通的 form字段一样添加一个 captcha 字段就可以了!

5、修改 login.html

由于我们前面是手动生成的 form 表单,所以还要修改一下,添加 captcha 的相关内容,如下所示:

<div class="form-group">
  {{ login_form.captcha.errors }}
  {{ login_form.captcha.label_tag }}
  {{ login_form.captcha }}
</div>

这里额外增加了一条{{ login_form.captcha.errors }}用于明确指示用户,你的验证码不正确。

6、查看效果

重启服务器,进入登录页面,尝试用用户名错误、密码不对、验证码不对、全对的不同情况,看看我们新增的四位验证码的效果如何。

就是这么简单!我们加入了一个防止机器人或者恶意登录的图形验证码功能,虽然界面难看了点,但底子是好的,你可以根据需要进行美化。其中验证图形码是否正确的工作都是在后台自动完成的,只需要使用 is_valid()这个 forms 内置的验证方法就一起进行了,完全不需要在视图函数中添加任何的验证代码,非常方便快捷!

 

转载于:https://www.cnblogs.com/sunBinary/p/10459284.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IdeaCMS网站内容管理系统是主要服务于中小企业的CMS内容管理系统,一般的开发人员能够使用系统提供的模块以最低的成本、最少的人力投入在最短的时间内架设一个功能齐全、性能优异的网站平台。 IdeaCMS是基于ASP Access/ASP MSSQL开发的网站内容管理系统,这样一般的开发人员都能比较轻松的掌握本系统。目前本系统集成了简介类模块,新闻类模块,产品类模块,视频类模块,图片类模块,下载类模块。并且有评论,订单,应聘等插件供选择。并支持生成静态网站,方便搜索引擎收录。 本系统从2007年发布至今经历了1.0,1.1,2.0,3.0三个版本,受到了许多用户的肯定以及市场的检验,并不断吸收来自各方面的发展建议和成功经验,其功能不断完善和发展,目前系统不仅适用于企业网站,也适合门户、政府、学校、以及其他各种资讯类网站使用。 修正可能通过后台修改模板页拿shell漏洞 IdeaCMS4.0版本更新功能: 1.改进后台登陆及后台管理界面 2.增加会员功能(加强版本) 3.增加图片缩略图功能 4.后台可更换网站logo图片 5.可为不同栏目添加不同banner图片 6.后台可控制栏目是否显示 7.后台修正管理员分级不能使用情况 8.修正后台添加内容不能包含敏感字符 9.后台发布文章可选择阅读权限(加强版本) 10.添加当前位置标签{ideacms:sitepath} 11.添加缩略图标签[对应栏目:spic] 12.添加信息所属栏目标签[对应栏目:typename] 13.栏目可赋予不同级别样式 ideacms4.0build20120418GBK更新: 修正后台产品搜索时类别为下载类问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值