《The Django Book》学习笔记
模板主要用来使表现与样式分离,模板通常用于产生HTML,但是Django的模板也能产生任何基于文本格式的文档。
如何使用模板系统
以下是一个简单的模板例子:
<html> <head><title>Ordering notice</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> #filter过滤器 <p>Here are the items you've ordered:</p> <ul> {% for item in item_list %} #大括号和百分号扩起来的是模板标签(template tag)
<li>{{ item }}</li> {% endfor %} </ul> {% if ordered_warranty %} <p>Your warranty information will be included in the packaging.</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>
使用Django模板系统的基本规则: 写模板,创建 Template 对象,创建 Context , 调用 render() 方法。
#在manage.py所在目录用 python manage.py shell 命令启动交互界面,避免配置麻烦的环境变量
>>> from django import template >>> t = template.Template('My name is {{ name }}.') #Template方法以模板为参数创建模板对象 >>> c = template.Context({'name': 'Adrian'}) #创建context对象,一个context是一系列变量和它们值的集合。 >>> print t.render(c) #render方法使用context对象进行模板渲染 My name is Adrian. >>> c = template.Context({'name': 'Fred'}) >>> print t.render(c) My name is Fred.
一个模板对象可以渲染多个context对象
可以通过句点来访问对象的属性和方法:
>>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name }} is {{ person.age }} years old.') >>> c = Context({'person': person}) #键值与模板文本内的变量对应 >>> t.render(c) u'Sally is 43 years old.'
>>> from django.template import Template, 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'
句点查找规则可概括为: 当模板系统在变量名中遇到点时,按照以下顺序尝试进行查找:
-
字典类型查找 (比如 foo["bar"] )
-
属性查找 (比如 foo.bar )
-
方法调用 (比如 foo.bar() )
-
列表类型索引查找 (比如 foo[bar] )
模板标签和过滤器:
{% if today_is_weekend %} <p>Welcome to the weekend!</p> {% else %} <p>Get back to work.</p> {% endif %} #模板标签必须成对出现
{% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not )
{% if %} 标签不允许在同一个标签中同时使用 and 和 or ,因为逻辑上可能模糊的,但是多次使用同一个逻辑操作符是没有问题的
没有 {% elif %} 标签, 请使用嵌套的`` {% if %}`` 标签来达成同样的效果
一定要用 {% endif %} 关闭每一个 {% if %} 标签。
{% for athlete in athlete_list %}
<p>{{ athlete.name }}</p>
{% empty %} #可选
<p>There are no athletes. Only computer programmers.</p>
{% endfor %}
`` for`` 标签支持一个可选的`` {% empty %}`` 分句,表示在for之后内容为空时候的操作
Django不支持退出循环操作,也不支持continue语句。
在每个`` {% for %}``循环里有一个称为`` forloop`` 的模板变量。这个变量有一些提示循环进度信息的属性,仅仅能够在循环中使用:
- forloop.counter :表示当前循环的执行次数。forloop.counter0 类似于 forloop.counter ,但是它是从0计数的
- forloop.revcounter :表示循环中剩余项的整型变量,最后一次循环会被置1。forloop.revcounter0 类似于 forloop.revcounter ,但它以0做为结束索引
- forloop.first :是一个布尔值,为真表示循环是第一次执行
- forloop.last :是一个布尔值,在最后一次执行循环时被置为True
- forloop.parentloop: 是一个指向当前循环的上一级循环的 forloop 对象的引用(在嵌套循环的情况下),如下例子:
{% for country in countries %} {% for city in country.city_list %} <p>Country #{{ forloop.parentloop.counter }}</p> <p>City #{{ forloop.counter }}</p> {% endfor %} {% endfor %}
Django模板系统不允许我们在模板中执行Python的语句,但是可以使用 ifequal/ifnotequal 简单的标签
注释:
{# This is a comment #} #使用{# #}提供注释,但用这种语法的注释不能跨越多行
过滤器:
{{ name|lower }} #转换name变量内容为小写
{{ my_list|first|upper }} #管道可以套接,表示列表第一项全部大写
{{ bio|truncatewords:"30" }} #有些过滤器有参数,将显示变量 bio 的前30个词
几个最重要的过滤器:
- addslashes : 添加反斜杠到任何反斜杠、单引号或者双引号前面。
- date : 按指定的格式字符串参数格式化 date 或者 datetime 对象,如本文最开始的范例
- length : 返回变量的长度
模板加载
业务逻辑应该和表现逻辑相对分开 ,所以将模板放在单独的文本文件中,然后在python代码中加载。
Django 提供了一种使用方便且功能强大的 API ,用于从磁盘中加载模板。要使用此模板加载API,首先你必须将模板的保存位置告诉框架。 设置的保存文件就是我们前一章节讲述ROOT_URLCONF配置的时候提到的 settings.py。以下是setting.py中设置模板路径的项:
TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django/templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. )
设置好模板路径之后,更改视图文件view.py的代码:
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') #get_template方法读取模板 html = t.render(Context({'current_date': now})) return HttpResponse(html)
更简洁的方法(模板加载、上下文创建、模板解析和HttpResponse 创建工作均在对 render_to_response() 的调用中完成):
from django.shortcuts import render_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 时所使用的字典,字典用来渲染current_datetime.html中的变量。 如果不提供第二个参数, render_to_response() 使用一个空字典。
调用模板时也可以使用子目录形式。
return render_to_response('dateapp/current_datetime.html', {'current_date': now})
模板继承
{% include %} 标签允许在(模板中)包含其它的模板的内容,但这并非模板继承。
模板继承第一步是定义 基础模板 (base.html), 该框架之后将由 子模板 所继承。在子模板中由{% extends "base.html" %}装载父模板,思想类似与类的继承。
你可以根据需要使用任意多的继承次数。 使用继承的一种常见方式是下面的三层法:
- 创建 base.html 模板,在其中定义站点的主要外观感受。 这些都是不常修改甚至从不修改的部分。
- 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对 base.html 进行拓展,并包含区域特定的风格与设计。
- 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。
这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工作。