认识django2.0读书笔记(4)---第四章 模板

时间:2022-01-02 20:16:49

文档下载地址:Django_2.0_中文教程  http://download.csdn.net/detail/julius_lee/6620099

在线地址:http://djangobook.py3k.cn/2.0/

Django 2.0 Book 关键内容记录,主要是为了帮助记忆和理清整个框架,同时以后忘了可以查看,回想。


为什么要模板?

前面都是将HTML硬编码到视图views.py中,这样导致,对页面设计修改时需要对python代码进行修改;python代码和HTML不方便分配给不同的人进行编写,分开编写还可以缩短时间,提高效率。

1、  模板系统基本知识

模板:一个文本,用于分离文档的表现形式和内容。定义如何显示基本逻辑(模板标签),常用于产生HTML,也可以产生其他文本格式。

一个模板示例:

<html>

<head><title>Orderingnotice</title></head>

 

<body>

 

<h1>Ordering notice</h1>

 

<p>Dear {{ person_name }},</p>

 

<p>Thanks for placing an order from{{ company }}. It's scheduled to

ship on {{ship_date|date:"F j, Y" }}.</p>

 

<p>Here are the items you'veordered:</p>

 

<ul>

{% for item in item_list %}

   <li>{{ item }}</li>

{% endfor %}

</ul>

 

{% if ordered_warranty %}

   <p>Your warranty information will be included in thepackaging.</p>

{% else %}

   <p>You didn't order a warranty, so you're on your own when

   the products inevitably stop working.</p>

{% endif %}

 

<p>Sincerely,<br />{{ company}}</p>

 

</body>

</html>

说明:

1.变量:两个大括号括起来的字符{{ 变量 }}

2.模板标签:被大括号和百分号包含的文本{% if  XXXXX %},可以有for或者if等判断,对应可以有{% else %},{%end if %}等

3.{{ ship_date|date:"F j, Y" }},可以使用过滤器,即将ship_date传递给date过滤器,通过|管理来调用过滤器

2、  如何使用模板系统

基本方式:

模板代码字符串创建template对象—>调用render模板对象方法,传入一套变量context;返回基于模板的展现字符串,变量和标签被context值替换

>>> from django import template

>>> t = template.Template('My nameis {{ name }}.')

>>> c = template.Context({'name':'Adrian'})

>>> print t.render(c)

My name is Adrian.

>>> c = template.Context({'name':'Fred'})

>>> print t.render(c)

My name is Fred.

 

3、  创建模板对象

创建template对象---直接实例化。

在project目录中运行python manage.py shell 进行交互(manage.py shell命令有一个重要的不同: 在启动解释器之前,它告诉Django使用哪个设置文件。)

>>> from django.template importTemplate

>>> t = Template('My name is {{ name }}.')

>>> print t

4、  模板渲染

使用context传递数据给Template对象,其中context是一系列变量和变量值的集合,类似于字典

>>> from django.template importContext, Template

>>> t = Template('My name is {{name }}.')

>>> c = Context({'name':'Stephane'})

>>> t.render(c)

u'My name is Stephane.'
注意:

t.render(c)返回的是一个非字符串的unicode对象,这要有很多好处。

变量名:由英文字符开始,可以包含数字或下划线,小数点,对大小写敏感

示例:

>>> from django.template importTemplate, Context

>>> raw_template ="""<p>Dear {{ person_name }},</p>

...

... <p>Thanks for placing an orderfrom {{ company }}. It's scheduled to

... ship on {{ ship_date|date:"F j,Y" }}.</p>

...

... {% if ordered_warranty %}

... <p>Your warranty information willbe included in the packaging.</p>

... {% else %}

... <p>You didn't order a warranty,so you're on your own when

... the products inevitably stopworking.</p>

... {% endif %}

...

... <p>Sincerely,<br />{{company }}</p>"""

>>> t = Template(raw_template)

>>> import datetime

>>> c = Context({'person_name':'John Smith',

...    'company': 'Outdoor Equipment',

...    'ship_date': datetime.date(2009, 4, 2),

...    'ordered_warranty': False})

>>> t.render(c)

u"<p>Dear JohnSmith,</p>\n\n<p>Thanks for placing an order from Outdoor

Equipment. It's scheduled to\nship on April2, 2009.</p>\n\n\n<p>You

didn't order a warranty, so you're on yourown when\nthe products

inevitably stop working.</p>\n\n\n<p>Sincerely,<br/>Outdoor Equipment

</p>"
说明

1)  导入django.template中的Template和Context

2)  Raw_template 保存原始模板文本

3)  创建模板对象t

4)  创建Context对象c

5)  最后调用render方法传递context参数,返回渲染后的方法(替换模板变量和执行块标签)

5、  同一模板,多个上下文

示例:

>>> from django.template importTemplate, Context

>>> t = Template('Hello, {{ name}}')

>>> print t.render(Context({'name':'John'}))

Hello, John

>>> printt.render(Context({'name': 'Julie'}))

Hello, Julie

>>> printt.render(Context({'name': 'Pat'}))

Hello, Pat
这样就可以实现多次调用render()方法

如加一个循环:

t = Template('Hello, {{ name }}')

for name in ('John', 'Julie', 'Pat'):

    print t.render(Context({'name': name}))

6、  深度变量的查找

即通过模板系统简洁的处理复杂数据结构list,dict,和自定义对象,一般使用点字符

1)示例:传递python dict

>>> from django.template importTemplate, Context

>>> person = {'name': 'Sally','age': '43'}#字典

>>> t = Template('{{ person.name}} is {{ person.age }} years old.')#XX.xxx进行传递

>>> c = Context({'person':person})

>>> t.render(c)

u'Sally is 43 years old.'

2)示例:访问对象的属性

>>> from django.template importTemplate, Context

>>> import datetime

>>> d = datetime.date(1993, 5, 2)

>>> d.year#和python一样

1993

>>> d.month

5

>>> d.day

2

>>> t = Template('The month is {{date.month }} and the year is {{ date.year }}.')

>>> c = Context({'date': d})#属性传递 d = datetime.date(1993, 5, 2)

>>> t.render(c)

u'The month is 5 and the year is 1993.'

3)示例:用于自定义类

>>> from django.template importTemplate, Context

>>> class Person(object):

...    def __init__(self, first_name, last_name):

...        self.first_name, self.last_name = first_name, last_name

>>> t = Template('Hello, {{person.first_name }} {{ person.last_name }}.')

>>> c = Context({'person': Person('John','Smith')})#传递自定义类person的属性

>>> t.render(c)

u'Hello, John Smith.'

4)示例:引用对象的方法

>>> from django.template importTemplate, Context

>>> t = Template('{{ var }} -- {{var.upper }} -- {{ var.isdigit }}')

>>> t.render(Context({'var':'hello'}))#使用了字符串自带的大写转换和类别判断

u'hello -- HELLO -- False'

>>> t.render(Context({'var':'123'}))

u'123 -- 123 -- True'

5)  示例:访问列表索引

>>> from django.template importTemplate, Context

>>> t = Template('Item 2 is {{items.2 }}.')#即使用了list的索引引用的方法

>>> c = Context({'items':['apples', 'bananas', 'carrots']})

>>> t.render(c)

u'Item 2 is carrots.'

总结:

在模板系统中,变量名遇到点时的查找顺序:字典类型->属性查找->方法调用->列表索引查找。这就是深度变量查找的顺序。

7、  方法调用行为

#《《这个没有理解清楚,全文摘录》》

方法调用比其他类型的查找略为复杂一点。 以下是一些注意事项:

在方法查找过程中,如果某方法抛出一个异常,除非该异常有一个 silent_variable_failure 属性并且值为 True ,否则的话它将被传播。如果异常被传播,模板里的指定变量会被置为空字符串,比如:

>>> t = Template("My name is{{ person.first_name }}.")

>>> class PersonClass3:

...    def first_name(self):

...        raise AssertionError, "foo"

>>> p = PersonClass3()

>>>t.render(Context({"person": p}))

Traceback (most recent call last):

...

AssertionError: foo

 

>>> classSilentAssertionError(AssertionError):

...    silent_variable_failure = True

>>> class PersonClass4:

...    def first_name(self):

...        raise SilentAssertionError

>>> p = PersonClass4()

>>>t.render(Context({"person": p}))

u'My name is .'

仅在方法无需传入参数时,其调用才有效。 否则,系统将会转移到下一个查找类型(列表索引查找)。

显然,有些方法是有副作用的,好的情况下允许模板系统访问它们可能只是干件蠢事,坏的情况下甚至会引发安全漏洞。

例如,你的一个BankAccount 对象有一个 delete()方法。 如果某个模板中包含了像 {{ account.delete }}这样的标签,其中`` account`` 又是BankAccount 的一个实例,请注意在这个模板载入时,account对象将被删除。

要防止这样的事情发生,必须设置该方法的 alters_data 函数属性:

def delete(self):

    #Delete the account

delete.alters_data = True
模板系统不会执行任何以该方式进行标记的方法。 接上面的例子,如果模板文件里包含了 {{ account.delete}} ,对象又具有delete()方法,而且delete() 有alters_data=True这个属性,那么在模板载入时, delete()方法将不会被执行。 它将静静地错误退出。

8、  无效变量的处理

如果变量不存在,一般用空串表示

示例:

>>> from django.template importTemplate, Context

>>> t = Template('Your name is {{name }}.')

>>> t.render(Context())

u'Your name is .'#没有引用值

>>> t.render(Context({'var':'hello'}))

u'Your name is .'#没有引用值

>>> t.render(Context({'NAME': 'hello'}))

u'Your name is .'#没有引用值
但是这种失败没有提示,存在一定弊端。

9、  context 对象

可以传递fullpopulated的字典给context进行初始化。初始化后可以使用python字典语法进行添加或删除

>>> from django.template importContext

>>> c = Context({"foo":"bar"})#full populated的字典给context进行初始化

>>> c['foo']

'bar'

>>> del c['foo']

>>> c['foo']

Traceback (most recent call last):

  ...

KeyError: 'foo'

>>> c['newvariable'] = 'hello'#字典的增加

>>> c['newvariable']

'hello'


10、基本模板标签

1)  标签 if

{% if % }标签检查一个变量,如果为真,则执行其与{% end if %}之间的内容

{% else % }标签为可选项,根据需要选择

注意:布尔值为False的主要有:

空list[],空元组(),空字典{},空字串’’,零值0,特殊对象None,对象False

       接受and,or,或not关键字判断多个变量

示例:

{% if athlete_list and coach_list %}

   Both athletes and coaches are available.

{% endif %}

 

{% if not athlete_list %}

   There are no athletes.

{% endif %}

 

{% if athlete_list or coach_list %}

   There are some athletes or some coaches.

{% endif %}


不兼容内容:

if中and和or不可以同时使用

系统不支持用圆括号组合比较操作

可以多次使用一个操作符,但不能组合不同的操作符

{% if athlete_list and coach_list or cheerleader_list %}#不合法

考虑用下面方法代替

{% if athlete_list %}

   {% if coach_list or cheerleader_list %}

       We have athletes, and either coaches or cheerleaders!

   {% endif %}

{% endif %}
 

2)  标签 for

可以进行序列上的迭代,类似python的for语法,模板系统渲染{% for %}与{% end for %}之间的内容

示例1:循环一个list

<ul>

{% for athlete in athlete_list %}

   <li>{{ athlete.name }}</li>

{% endfor %}

</ul>


示例2:reversed 反向迭代

{% for athlete in athlete_list reversed %}

...

{% endfor %}

也可以进行嵌套使用

`` for`` 标签支持一个可选的`` {% empty %}`` 分句,通过它我们可以定义当列表为空时的输出内容下面的例子与之前那个等价:

{% for athlete in athlete_list %}

   <p>{{ athlete.name }}</p>

{% empty %}

   <p>There are no athletes. Only computer programmers.</p>

{% endfor %}

不支持退出break和continue语句

进度提示模板变量:forloop

示例:forloop

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

{% for item in todo_list %}

   <p>{{ forloop.counter }}: {{ item }}</p>

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

forloop.revcounter 是表示循环中剩余项的整型变量。 在循环初次执行时 forloop.revcounter 将被设置为序列中项的总数。最后一次循环执行中,这个变量将被置1。

forloop.revcounter0 类似于 forloop.revcounter ,但它以0做为结束索引。在第一次执行循环时,该变量会被置为序列的项的个数减1。

forloop.last 是一个布尔值;在最后一次执行循环时被置为True。 一个常见的用法是在一系列的链接之间放置管道符(|)

 

{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}

上面的模板可能会产生如下的结果:

Link1 | Link2 | Link3 | Link4

另一个常见的用途是为列表的每个单词的加上逗号。

 Favorite places:

{% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{% endfor %}

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 %}
forloop 变量仅仅能够在循环中使用。在模板解析器碰到{% endfor %}标签后,forloop就不可访问了。


3)  标签:ifequal与ifnotequal

{% ifequal %}标签比较两个值,相等时,显示{% ifequal %} 与{% endifequal %}间的所有值。

示例:

{% ifequal user currentuser %}

   <h1>Welcome!</h1>

{% endifequal %}
      支持{% else % }标签

示例:

{% ifequal section 'sitenews' %}

   <h1>Site News</h1>

{% else %}

   <h1>No News Here</h1>

{% endifequal %}
       支持参数只有:模板变量,字符串,整数,小数,如:

{% ifequal variable 1 %}

{% ifequal variable 1.23 %}

{% ifequal variable 'foo' %}

{% ifequal variable "foo" %}

不支持python字典类型,列表类型,布尔类型,如:

{% ifequal variable True %}

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

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


4)  注释

单行注释使用{# XXXXXXX #},(不能跨行注释)不会在渲染时输出;

多行使用{% comment %} XXXX {%endcomment%}

11、 过滤器

在变量显示前修改它的值,使用管道字符|

{{ name|lower}}
作用:显示变量name被过滤器lower转换为小写后的结果

也可以进行套接

{{my_list|first|upper }}

常用过滤器

addslashes : 添加反斜杠到任何反斜杠、单引号或者双引号前面。这在处理包含JavaScript的文本时是非常有用的。

date : 按指定的格式字符串参数格式化 date 或者 datetime 对象, 范例:

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

Length:返回变量的长度

12、  在视图中使用模板

1)  模板加载

1.设置模板的保存位置,对settings.py 的TEMPLATE_DIR进行设置

TEMPLATE_DIRS =[os.path.join(BASE_DIR, 'templates')],这种不添加也可以,使用绝对路径自动添加。

       手动添加:

# Comma correctly in place.

TEMPLATE_DIRS = (

   '/home/django/mysite/templates',#单元素必须用逗号隔开圆括号

)

     2.修改视图代码

示例:

from django.template.loader import get_template#处理模板及路径

from django.template import Context

from django.http import HttpResponse

import datetime

 

def current_datetime(request):

   now = datetime.datetime.now()

    t= get_template('current_datetime.html')

   html = t.render(Context({'current_date': now}))

   return HttpResponse(html)
使用loader自动加载模板

在模板目录中创建模板代码current_datetime.html,再浏览器解析即可达到同样的效果。

       3.render_to_response()

作用:一次性的载入某个模板,渲染,然后作为HttpResponse返回

示例代码简化为:

from django.shortcuts importrender_to_response

import datetime

 

def current_datetime(request):

   now = datetime.datetime.now()

   return render_to_response('current_datetime.html', {'current_date':now})


render_to_response() 的第一个参数必须是要使用的模板名称。 如果要给定第二个参数,那么该参数必须是为该模板创建 Context 时所使用的字典。 如果不提供第二个参数, render_to_response() 使用一个空字典。

       4.locals()

       简化临时变量和临时模板的命名,其为python内建函数,返回所有局部变量名称与值的映射值,为一个字典。

示例进一步简化:

def current_datetime(request):

   current_date = datetime.datetime.now()

   return render_to_response('current_datetime.html', locals())


       5.get_template()中使用目录

应对模板存放于不用的模板目录中。

return render_to_response('dateapp/current_datetime.html',{'current_date': now})#就是在前面加一个路径dateapp/

       6.内建模板标签 include

允许在模板中包含其他模板的内容,进行代码复用;

示例:

{% include 'nav.html' %}

{% include "nav.html" %}
下面的例子包含了includes/nav.html 模板的内容:

{% include 'includes/nav.html' %}

下面的例子包含了以变量template_name 的值为名称的模板内容:

{% include template_name %}

13、  模板继承

解决共用页面所引起的的代码重复和冗余,此法比{%include%}更适合

方法:先构造一个基础框架模板,然后在子模板中对所包含站点公共部分和定义块进行重载;

示例:

基本模板 base.html

<!DOCTYPE HTML PUBLIC "//W3C//DTD HTML 4.0.1//EN">
<html lang="en">
<head>#header
    <title>{% block title %}{% endblock %}</title>#子模板重载部分以{% block %}告知
</head>
<body>
    <h1>My helpful timestamp site</h1>
    {% block content %}{% endblock %}
    {% block footer %}
    <hr>#footer
    <p>Thanks for visiting my site .</p>
    {% endblock %}
</body>
</html>

示例:使用current_datetime.html来使用基本模板

{% extends "base.html" %}

 

{% block title %}The current time{%endblock %}

 

{% block content %}

<p>It is now {{ current_date}}.</p>

{% endblock %}


执行过程:

加载current_datetime.html,发现{% extend %}标签,模板引擎装载父模板base.html,然后对block标签的内容进行替换