python后台架构Django教程——templates模板

版权声明:本文为博主原创文章,转载请注明来源。开发合作联系82548597@qq.com https://blog.csdn.net/luanpeng825485697/article/details/79266653

全栈工程师开发手册 (作者:栾鹏)

本文衔接至python后台架构Django开发全解。

有其他问题请先阅读:http://blog.csdn.net/luanpeng825485697/article/details/79228895

前面的部分我们创建了一个名为hello的django项目,一个名为app1的应用,连接了mysql数据库,在app1中创建了User和Diary两个model数据模型。并且学习了views视图函数。


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

模版是纯文本文件,可以生成任何基于文本的文件格式,比如HTML,XML,CSV等。

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

本节就来了解这些特殊的模版语法。

前面我们在views视图函数中学习了可以使用render函数、render_to_response等函数返回静态html模板视图、或将字典参数传递给模板视图,渲染动态html模板视图。

一个简单的渲染模板示例如下:

from django.shortcuts import render_to_response
from .models import User,Diary

# findalluser将数据库内存储的数据读出并展示出来。
def findalluser(request):
    allpeople = User.objects.all()  # 查询所有用户
    dict={
        'people_list':allpeople
    }
    return render_to_response("showuser.html",dict)  # 返回文件响应,第二个参数必须为字典

findalluser将数据库内存储的数据读出并结合html文件渲染出最后的响应hhtml源代码。这和jsp中的原理相同,python先将html文件的内容全部加载到内存中,再根据python的语法和传来的数据库数据生成html文件中python代码部分产生的文本,再将最终生成的html源代码返回到前端。

配置引擎

模板引擎通过settings.py文件中的TEMPLATES设置来配置。
配置可以参考
http://blog.csdn.net/luanpeng825485697/article/details/79253858
中的TEMPLATES配置

搜索过程

当我们在views的视图函数中加载、搜索模板时,如下

get_template('detail.html')

Django将按以下顺序查找story_detail.html:

/home/html/example.com/detail.html('django'引擎)
/home/html/default/detail.html('django'引擎)
/home/html/jinja2/detail.html('jinja2'引擎)

当我们有多个app,并且在多个app下有相同模板名称时,例如
app1/templates/detail.html
app2/templates/detail.html

无论我们在哪个app的视图函数中搜索“detail.html”这个模板,都将只能搜索到第一个detail模板。所以我们要通过路径来区分模板。将文件目录构建成
app1/templates/app1/detail.html
app2/templates/app2/detail.html

这样我们在视图函数使用”app2/detail.html”的路径就能搜索不同app下的模板。

基本语法

1、模板上下文

views视图函数传递给模板的只能是字典参数。这个字典参数被称为模板的上下文context。比如:

render_to_response("showuser.html",{'key1':'value1','key2':object2})

在模板文件中可以直接通过键key来获取调用值value。比如下面的代码就表示字符串'value1'

{{ key1}}

模板能够访问到的不仅仅是对象的属性(比如字段名称)和视图中传入的变量,还可以执行对象的方法。

比如QuerySets提供了count()方法来计算含有对象的总数。

{{ users.count }}

你可以像这样获取所有关于当前用户集合的数目

2、变量

变量看起来就像是这样: {{ variable }}。

当模版引擎遇到一个变量,它将从上下文context中获取这个变量的值,然后用值替换掉它本身。

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

  • 字典查询(Dictionary lookup)
  • 属性或方法查询(Attribute or method lookup)
  • 数字索引查询(Numeric index lookup)

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

注意:像{{ foo.bar }}这种模版表达式中的“bar”,如果在模版上下文中存在,将解释为一个字面意义的字符串而不是使用变量bar的值 。

3、过滤器

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

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

过滤器带参:
{{ list|join:”, ” }}。使用逗号和空格去连接一个列表中的元素

过滤器的作用是对变量进行预处理,相当于函数的功能,过滤器的工作都可以在views视图函数中完成。也可以通过自定义函数来实现自定义过滤器。在后面的自定义过滤器中我们会了解。

例1、default

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

{{ value|default:"nothing" }}

例2、length

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

{{ value|length }}

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

为模版过滤器提供参数的方式是:过滤器后加个冒号,再紧跟参数,中间不能有空格!

目前只能为过滤器最多提供一个参数!

过滤器 说明
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
urlize url转成可点击的链接
urlizetrunc urlize的截断方式
wordcount 单词计数
wordwrap 单词包裹
yesno 将True,False和None,映射成字符串‘yes’,‘no’,‘maybe’

4、标签

标签看起来像是这样的: {% tag %}。

标签比变量复杂得多,有些用于在输出中创建文本,有些用于控制循环或判断逻辑,有些用于加载外部信息到模板中供以后的变量使用。

一些标签需要开始和结束标签(即 {% 标签 %} … 标签 内容 … {% ENDTAG %})。

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

1. for循环标签

<ul>
{% for user in people_list %}
    <li>{{ user.username }}</li>
{% endfor %}
</ul>

for循环中可以通过forloop.counter来获取你当前循环的次数。forloop.counter是DJango模板系统专门提供的一个变量,一般用来给循环项目添加有序数标。

2. 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 %}

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

3. autoescape

控制自动转义是否可用。参数是on或off。 该标签会以一个endautoescape作为结束标签.

{% autoescape on %}
    {{ body }}
{% endautoescape %}

4. block

block标签可以被子模板覆盖。

5. comment

在{% comment %}和{% endcomment %}之间的内容会被忽略,作为注释。

比如,当要注释掉一些代码时,可以用此来记录代码被注释掉的原因。

例如:

<p>Rendered text with {{ pub_date|date:"c" }}</p>
{% comment "Optional note" %}
    <p>Commented out text with {{ create_date|date:"c" }}</p>
{% endcomment %}

6. csrf_token

这个标签用于跨站请求伪造保护。常用于为form表单提供csrf令牌。

7. cycle

每当这个标签被访问,返回它的下一个元素。第一次访问返回第一个元素,第二次访问返回第二个参数,以此类推. 一旦所有的变量都被访问过了,就会回到最开始的地方,重复下去。这个标签在循环中特别有用:

{% for o in some_list %}
    <tr class="{% cycle 'row1' 'row2'%}">
        ...
    </tr>
{% endfor %}

第一次迭代产生的HTML引用了row1类,第二次则是row2类,第三次又是row1 类,如此类推。

也可以使用变量, 例如,如果你有两个模版变量:rowvalue1和rowvalue2, 可以让他们的值像这样替换:

{% for o in some_list %}
    <tr class="{% cycle 'row1' rowvalue2 'row3' %}">
        ...
    </tr>
{% endfor %}

在某些情况下,可能需要连续引用一个当前循环的值,而不前进到下一个循环值。要达到这个目的,只需使用as来给{% cycle %}取一个别名,就像这样:

<tr>
    <td class="{% cycle 'row1' 'row2' as rowcolors %}">...</td>
    <td class="{{ rowcolors }}">...</td>
</tr>
<tr>
    <td class="{% cycle rowcolors %}">...</td>
    <td class="{{ rowcolors }}">...</td>
</tr>

将输出:

<tr>
    <td class="row1">...</td>
    <td class="row1">...</td>
</tr>
<tr>
    <td class="row2">...</td>
    <td class="row2">...</td>
</tr>

8. debug

输出整个调试信息,包括当前上下文和导入的模块。

9. filter

通过一个或多个过滤器对内容过滤。需要结束标签endfilter。

例如:

{% filter force_escape|lower %}
    This text will be HTML-escaped, and will appear in all lowercase.
{% endfilter %}

10. include

加载指定的模板并以标签内的参数渲染。这是一种引入别的模板的方法,一定要将include和extend区分开!include类似Python的import。

{% include "foo/bar.html" %}

也可以使用变量名template_name:
{% include template_name %}   

11. spaceless

删除HTML标签之间的空白,包括制表符和换行。

{% spaceless %}
    <p>
        <a href="foo/">Foo</a>
    </p>
{% endspaceless %}

五、注释

要注释模版中一行的部分内容,使用注释语法:{# #}。

{# {% if foo %}bar{% else %} #}

以上是单行注释(在{# …. #}中,不允许有新行)。

如果需要注释掉模版中的多行内容,请使用comment标签。

六、自动转义HTML

默认情况下,Django中的每个模板会自动转义每个变量。依次来避免跨站脚本攻击(Cross Site Scripting)(XSS)。也就是说,下面五个字符将被转义:

  • <会转换为&lt;
  • >会转换为&gt;
  • '(单引号)转换为&#39;
  • "(双引号)会转换为&quot;
  • &会转换为&amp;

但是,有时,模板变量含有一些你打算渲染成原始HTML的数据,你并不想转义这些内容。 例如,你可能会在数据库中储存一些HTML代码,并且直接在模板中嵌入它们。或者,你可能使用Django的模板系统来生成不是HTML的文本 – 比如邮件信息。要怎么办呢?

对于单个变量:

使用safe过滤器来关闭变量上的自动转义:

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

对于模板块:

要控制模板上的自动转义,将模板(或者模板中的特定区域)包裹在autoescape标签中,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 %}

过滤器的字符串参数不自动转义

过滤器的参数可以是字符串,所有这种字符串参数在插入模板时都不会进行任何自动转义,所以需要程序员自己转义。

{{ data|default:"3 &lt; 2" }}  {# 正确的做法#}
{{ data|default:"3 < 2" }}     {# 错误的做法#}

七、使用自定义标签和过滤器

一、前置步骤

第一步,在app中新建一个templatetags包(名字固定,不能变,只能是这个),和views.py、models.py等文件处于同一级别目录下。这是一个包!不要忘记创建__init__.py文件以使得该目录可以作为Python的包。

在添加templatetags包后,需要重新启动服务器,然后才能在模板中使用标签或过滤器。

将你自定义的标签和过滤器将放在templatetags包下的一个模块里。

这个模块的名字是后面载入标签时使用的标签名,所以要谨慎的选择名字以防与其他应用下的自定义标签和过滤器名字冲突,当然更不能与Django内置的冲突。

假设你自定义的标签/过滤器在一个名为poll_extras.py的文件中,那么你的app目录结构看起来应该是这样的:

app1/
    __init__.py
    models.py
    templatetags/
        __init__.py
        poll_extras.py
    views.py

为了让{% load xxx %}标签正常工作,包含自定义标签的app必须在INSTALLED_APPS中注册。然后你就可以在模板中像如下这样使用:

{% load poll_extras %}

在templatetags包中放多少个模块没有限制。只需要记住{% load xxx %}将会载入给定模块名中的标签/过滤器,而不是app中所有的标签和过滤器。

要在模块内自定义标签,首先,这个模块必须包含一个名为register的变量,它是template.Library的一个实例,所有的标签和过滤器都是在其中注册的。 所以把如下的内容放在你的模块的顶部:

from django import template

register = template.Library()

二、自定义模板过滤器

1、 编写过滤器

自定义过滤器就是一个带有一个或两个参数的Python函数:

注意:这个Python函数的第一个参数是你要过滤的对象,是必须要有的,第二个参数才是你自定义的参数。而且最多总共只能有两个参数,所以你只能自定义一个参数!这是过滤器的先天限制。

  • 变量的值:不一定是字符串形式。
  • 参数的值:可以有一个初始值,或者完全不要这个参数。

例如,在{{ var|foo:”bar” }}中,foo过滤器应当传入变量var和参数”bar”。

由于模板语言没有提供异常处理,任何从过滤器中抛出的异常都将会显示为服务器错误。

下面是一个定义过滤器的例子:

def cut(value, arg):
    """将value中的所有arg部分切除掉"""
    return value.replace(arg, '')

下面是这个过滤器的使用方法:

{{ somevariable|cut:"0" }}

2、注册过滤器

一旦你写好了过滤器函数,就需要注册它,方法是调用register.filter,比如:

@register.filter(name='cut')
def cut(value, arg):
    return value.replace(arg, '')

@register.filter
def lower(value):
    return value.lower()

三、自定义模板标签

标签比过滤器更复杂,因为标签可以做任何事情。Django提供了大量的快捷方式,使得编写标签比较容易。 对于我们一般的自定义标签来说,simple_tag是最重要的,它帮助你将一个Python函数注册为一个简单的模版标签。

八、静态文件

除了由服务器生成的HTML文件外,WEB应用一般需要提供一些其它的必要文件,比如图片文件、JavaScript脚本和CSS样式表等等,用来为用户呈现出一个完整的网页。在Django中,我们将这些文件统称为“静态文件”,因为这些文件的内容基本是固定不变的,不需要动态生成。

对于小项目,这些都不是大问题,你可以将静态文件放在任何你的web服务器能够找到的地方。但是对于大型项目,尤其是那些包含多个app在内的项目,处理那些由app带来的多套不同的静态文件是个麻烦活。

但这正是django.contrib.staticfiles的用途:它收集每个应用(和任何你指定的地方)的静态文件到一个统一指定的地方,并且易于访问。

使用静态文件

首先在你的app1目录中创建一个static目录。Django将在那里查找静态文件,这与Django在app1/templates/中寻找对应的模板文件的方式是一致的。

Django的STATICFILES_FINDERS设置项中包含一个查找器列表,它们知道如何从各种源中找到静态文件。 其中一个默认的查找器是AppDirectoriesFinder,它在每个INSTALLED_APPS下查找static子目录,例如我们刚创建的那个static目录。admin管理站点也为它的静态文件使用相同的目录结构。

在刚才的static目录中再新建一个app1文件夹,是用来区别当有多个app中存在相同静态文件名时便于区分。

在app1/static/app1/文件夹下新建style.css文件。内容为

td{
    color: green;
}

在使用静态文件前需要在模板中使用如下代码加载静态资源。

{% load static %}

然后可以在html模板中通过app1/style.css这个路径来访问app1/static/app1/style.css这个静态文件,与你如何访问templates模板的路径类似。

{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'app1/style.css' %}" />

PS:良好的目录结构是每个应用都应该创建自己的urls、views、models、templates和static,每个templates包含一个与应用同名的子目录,每个static也包含一个与应用同名的子目录。

展开阅读全文

没有更多推荐了,返回首页