模板的应用原理、过程

以mysite项目为例:

当一个url开始匹配开始时,先去mysite/mysite/urls.py 里匹配,然后里面会具体匹配到哪个应用,调用相应应用下的urls.py,(例如这里是polls)-> mysite/mysite/polls/urls.py 里面匹配到相应的url后,会调用polls应用下views.py里相应的函数 -> mysite/mysite/polls/views.py 最后使用render或render_to_response输出相应的模板 ->  mysite/mysite/polls/templates/polls/template.html 

如果这个模板还通过include引用了其他页面,或继承于其他模板页面,会继续加载相应的页面或模板

 

模板的配置方法

1、先在项目/setting.py下配置添加模板路径

setting.py内TEMPLATES 设置中添加一个DIRS 选项 :

        'DIRS': [os.path.join(BASE_DIR, 'templates')],

        其中BASE_DIR =os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

然后再在相应应用下面建立模板目录,放置模板文件,最终结构是templates/应用名称(例如polls)/模板文件(index.html等) ,使用时系统会自动查找templates目录,注意是templates目录,要自行加上plls路径,不然会找不到文件

 

模板中的注释

l  单行:{# This is acomment #}

l  多行:要使用标签了

{% comment %}

This is a

multi‐line comment.

{% endcomment %}

 

过滤器

模板过滤器是在变量被显示前修改它的值的一个简单方法。过滤器使用管道字符。

例1:小写转换

{{ name|lower }}

显示的内容是变量 ` name ` 被过滤器 lower 处理后的结果,它功能是转换文本为小写。

例2:日期格式化显示

{{ pub_date|date:"F j, Y" }}

例3:

{{ bio|truncatewords:"30" }}

这个将显示变量 bio 的前30个词。

 

基本的模板标签

include标签

内建模板标签: {% include %} 。该标签允许在(模板中)包含其它的模板的内容。标签的参数是所要包含的模板名称,可以是一个变量,也可以是用单/双引号硬编码的字符串。 每当在多个模板中出现相同的代码时,就应该考虑是否要使用 {% include %} 来减少重复。

例:

{% include ‘polls/foot.html’%}

 

if/else标签

标签检查(evaluate)一个变量,如果这个变量为真(即,变量存在,非空,不是布尔值假),系统会

显示在 {% if %} 和 {% endif %} 之间的任何内容

例:

{% if today_is_weekend %}

<p>Welcome to theweekend!</p>

{% endif %}

 

{% else %} 标签是可选的:

 

{% if today_is_weekend %}

<p>Welcome to theweekend!</p>

{% else %}

<p>Get back to work.</p>

{% endif %}

注意:

1、在Python和Django模板系统中,以下这些对象相当于布尔值的False,其余的都是True

l  空列表([] )

l  空元组(() )

l  空字典({} )

l  空字符串('' )

l  零值(0 )

l  特殊对象None

l  对象False(很明显)

2、{% if %} 标签不允许在同一个标签中同时使用 and 和 or ,因为逻辑上可能模糊的

       例:{% ifathlete_list and coach_list or cheerleader_list %}  这是错误的

3、系统不支持用圆括号来组合比较操作。如果你确实需要用到圆括号来组合表达你的逻辑式,考虑将它移到模板

之外处理,然后以模板变量的形式传入结果吧。或者,仅仅用嵌套的{% if %}标签替换吧,就像这样:

{% if athlete_list %}

       {% if coach_list orcheerleader_list %}

              We have athletes,and either coaches or cheerleaders!

{      % endif %}

{% endif %}

4、多次使用同一个逻辑操作符是没有问题的,但是我们不能把不同的操作符组合起来。例如,这是合法的:

{% if athlete_list or coach_list or parent_list or teacher_list %}

5、没有 {% elif %} 标签,并且一定要用 {% endif %} 关闭每一个 {% if %} 标签。

 

for标签

{%for %} 允许我们在一个序列上迭代。 与Python的 for 语句的情形类似,循环语法是 for X in Y ,Y是要迭代的序列而X是在每一个特定的循环中使用的变量名称。 每一次循环中,模板系统会渲染在 {% for%} 和{%endfor %} 之间的所有内容。

例:

{% for athlete in athlete_list %}

       <li>`athlete`.`name `</li>

{% endfor %}

 

在执行循环之前先检测列表的大小是一个通常的做法,当列表为空时输出一些特别的提示。

{%if athlete_list %}

       {% for athlete in athlete_list %}

              <p>` athlete`.`name`</p>

       {% endfor %}

{%else %}

       <p>There are no athletes. Only computerprogrammers.</p>

{%endif %}

 

for标签里有很多变量,方便我们的使用。在每个``{% for %}``循环里有一个称为`` forloop`` 的模板变量。这个变量有一些提示循环进度信息的属性。

l  forloop.counter 总是一个表示当前循环的执行次数的整数计数器。这个计数器是从1开始的,所以在第一

次循环时forloop.counter 将会被设置为1。

例:结果会显示1 2 3

y=[1,2,3]

{%for x in y %}

`forloop`.`counter `

{%endfor %}

l  forloop.counter0 类似于 forloop.counter ,但是它是从0计数的。第一次执行循环时这个变量会被设置

为0。

l  forloop.revcounter 是表示循环中剩余项的整型变量。在循环初次执行时 forloop.revcounter 将被设置

为序列中项的总数。最后一次循环执行中,这个变量将被置1。

l  forloop.revcounter0 类似于 forloop.revcounter,但它以0做为结束索引。在第一次执行循环时,该变

量会被置为序列的项的个数减1。

l  forloop.first 是一个布尔值,如果该迭代是第一次执行,那么它被置为````

l  forloop.last 是一个布尔值;在最后一次执行循环时被置为True

l  forloop.parentloop 是一个指向当前循环的上一级循环的forloop对象的引用(在嵌套循环的情况下)。

例:

{%for country in countries %}

<table>

{%for city in country.city_list %}

<tr>

<td>Country#` forloop`.`parentloop`.`counter `</td>

<td>City#` forloop`.`counter `</td>

<td>`city `</td>

</tr>

{%endfor %}

</table>

{%endfor %}

 

注意:

l  Django不支持退出循环操作。 如果我们想退出循环,可以改变正在迭代的变量,让其仅仅包含需要迭代的项目。同理,Django也不支持continue语句,我们无法让当前迭代操作跳回到循环头部。

l  forloop 变量仅仅能够在循环中使用。 在模板解析器碰到{% endfor %}标签后,forloop就不可访问了

 

ifequal/ifnotequal标签

{%ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。

例:比较两个模板变量 user 和 currentuser :

{% ifequal user currentuser %}

       <h1>Welcome!</h1>

{% endifequal %}

 

参数可以是硬编码的字符串,随便用单引号或者双引号引起来,所以下列代码都是正确的:

{% ifequal section 'sitenews' %}

       <h1>SiteNews</h1>

{% endifequal %}

 

和 {% if %} 类似, {% ifequal %} 支持可选的 {% else%} 标签:

{% ifequal section 'sitenews' %}

       <h1>SiteNews</h1>

{% else %}

       <h1>NoNews Here</h1>

{% endifequal %}

注意:

l  只有模板变量,字符串,整数和小数可以作为 {% ifequal %} 标签的参数。下面是合法参数的例子:

{% ifequal variable 1 %}

{% ifequal variable 1.23 %}

{% ifequal variable 'foo' %}

{% ifequal variable"foo" %}

l  其他任何类型,例如Python的字典类型、列表类型、布尔类型,不能用在 {% ifequal %} 中。 下面是些错误的

例:

{% ifequal variable True %}

{% ifequal variable [1, 2, 3]%}

{% ifequal variable {'key':'value'} %}

l  如果你需要判断变量是真还是假,请使用 {% if %} 来替代 {% ifequal %}

 

模板继承

为了减少开发中代码的书写,除了使用{% include %}共用的代码,更好的方法就是模板继承

模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。

使用方法:第一步是定义继承模板,一个基本的html页面,页面中{% block blockname %} 内容 {% endblock %} 里的内容就是可以重载、添加或保留的那些块。当一个页面继承了所定义的模板,它可以选择自定义{% block blockname %} {% endblock %}之间的内容,如果不去改变就会沿用原有设置

例(在视图中使用模板):

1、先定义一个模板base.html

<!DOCTYPEHTML PUBLIC "‐//W3C//DTD HTML 4.01//EN">

<html>

<head>

<title>{%block title %}标题内容{% endblock %}</title>

</head>

<body>

{%block content %}内容<h1>My helpful timestamp site</h1>{% endblock %}

{%block footer %}

<hr>

<p>Thanksfor visiting my site.页脚</p>

{%endblock %}

</body>

</html>

 

2、然后在extends.html页面中继承base.html

{%extends "polls/base.html" %}        #这里的路径要注意!django只会查找每个应用的templates根目录,再下一层的目录要手动写上去

{%block title %} dx site {% endblock %}

{%block content %} <h2> dx content </h2> {% endblock %}

 

3、然后在polls应用下的view.py 定义一个用于测试继承的函数

defextends_test(request):

      returnrender_to_response('polls/extends.html')

 

4、再在polls应用下的url.py定义一个新的url匹配规则

#ex: /polls/extends/

       url(r'extends/$', views.extends_test, name='extends_test'),

至此,模板的继承应用就实现了

注意:

l  如果在模板中使用 {%extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作

用。

l  {% extends %} 对所传入模板名称使用的加载方法和 get_template() 相同。 也就是说,会将模板名称被添

加到 TEMPLATE_DIRS 设置之后。

l  多数情况下, {%extends %} 的参数应该是字符串,但是如果直到运行时方能确定父模板名,这个参数也

可以是个变量。 这使得你能够实现一些很酷的动态功能

 

其他技巧

当我们利用render或render_to_response调用模板输出的时候,可以利用locals()传入所有的局部变量到模板里,这样就可以偷懒写一个locals()就可以了。