最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Django框架模板从基础入门到进阶
时间:2015-07-25 编辑:简简单单 来源:一聚教程网
Django框架模板基础
模板使用
模板基本由两个部分组成,一是HTML代码,二是逻辑控制代码。
逻辑控制的实现又基本由三个部分组成:
1. 变量的使用
{{ person_name }} #使用双大括号来引用变量
2. tag的使用
{% if ordered_warranty %} #使用大括号和百分号的组成来表示使用Django提供的
template tag
{% for item in item_list %}
{{ item }}
{% endfor %}
3. filter的使用
{{ ship_date|date:"F j, Y" }},ship_date变量传给data过滤器,data过滤器通过使用
"F j, Y"这几个参数来格式化日期数据。"|"代表类似Unix命令中的管道操作。
Template system不仅仅可以和view进行合作,也可以自己独立使用。
最基本的使用方法是:
1. 使用模板代码字符串作为参数,创建一个Template类
2. 创建模板代码中所需要的上下文Context对象,包含所需要的各个引用参数的值
3. 调用Template.render()方法,把template渲染成一个完整的字符串。
>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context({'name': 'Adrian'})
>>> print t.render(c)
>>> My name is Adrian.
还可以在template代码中使用dict索引,然后在context传入所需要的dict
>>> 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'
还可以使用列表索引,但是item.-1是不被允许的
>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
u'Item 2 is carrots.'
以上的使用方法被称为Dot Lookup方法。
使用dot lookup的访问函数功能时,需要注意的问题:
1. 当在模板代码中执行的函数抛出异常时,会一直向上层传播,除非这个异常中有一个参数
silent_variable_failure=True; 这样的话,这个出错的函数信息就会被渲染成空字符串。
>>> class SilentAssertionError(AssertionError):
... silent_variable_failure = True
>>> class PersonClass4:
... def first_name(self):
... raise SilentAssertionError
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
u'My name is .'
2. 很明显,调用函数会产生一些不好的结果,安全漏洞之类的,如果你有一个BankAccout,
然后在模板中写成{{ account.delete }}, 这样在渲染的时候,你的账号就被删除了。。。。
所以要在修改一下你的delete函数
def delete(self):
# Delete the account
delete.alters_data = True#缩进没有问题,把delete看成一个对象,设置它的alters_data属性。
这样在渲染的时候,就会变成failed silent。
当在渲染的时候,简单的key值没有找到时,会failed silent,变成空字符串,而不是大动干戈的
报错。
>>> from django.template import Template, Context
>>> t = Template('Your name is {{ name }}.')
>>> t.render(Context())
u'Your name is .'
>>> t.render(Context({'var': 'hello'}))
u'Your name is .'
Context对象也可以进行增删改值的操作。
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> c['newvariable'] = 'hello'
>>> del c['foo']
>>> c['foo']
使用python manage.py shell启动python交互式命令行窗口与一般直接启动python自带的
交互式命令行窗口的区别是前者会通过找一个DJANGO_SETTINGS_MODULE环境变量,
告诉Django导入settings.py的配置信息。
基本的tag和filter的用法
tag:
{% if %}的使用
可以使用and, or, not来组织你的逻辑。但不允许and和or同时出现的条件语句中。
没有{% elif %}这样的用法,只能用嵌套来实现多重if语句。
{% if athlete_list %}
{% else %}
{% if not coach_list %}
{% endif %}
{% endif %}
{% for %} 的使用
用来循环一个list,还可以使用resersed关键字来进行倒序遍历,一般可以用if语句来先
判断一下列表是否为空,再进行遍历;还可以使用empty关键字来进行为空时候的跳转。
{% for athlete in athlete_list resersed %}
{{ athlete.name }}
{% empty %}
{% endfor %}
for tag还提供了一些内置参数来提供模板循环的信息。
1. forloop.counter 当前循环计数,从1开始
{% for item in todo_list %}
{% endfor %}
2. forloop.counter0 当前循环计数,从0开始,标准索引方式
3. forloop.revcounter 当前循环的倒数计数,从列表长度开始
4. forloop.revcounter0 当前循环的倒数计数,从列表长度减1开始,标准
5. forloop.first bool值,判断是不是循环的第一个元素
6. forloop.last 同上,判断是不是循环的最后一个元素
7. forloop.parentloop 用在嵌套循环中,得到parent循环的引用,然后可以使用以上的参数
{% for country in countries %}
- {% for city in country.city_list %}
- {% endfor %}
{% endfor %}
ifequal和ifnotequal,一看就是直接比较值的tag,需要两个参数,用法比较有限,
只限于字符串,整数,小数的比较,什么列表,字典,元组不支持。
{% ifequal user currentuser %}
{% ifequal section "community" %}
{% endifequal %}
{% endifequal %}
{# #},模板中注释的用法,只能用在一行
如果要使用多行注释,要使用{% comment %}
{# This is a comment #}
{% comment %}
This is a
multi-line comment.
{% endcomment %}
filter:
filter用于变量在显示之前的一些简单的处理。使用类似管道的操作符"|",也可以进行链式操作
{{ name|lower }}
{{ my_list|first|upper }}
{{ bio|truncatewords:"30" }}
介绍几个重要的filter:
addslashes :给任何的反斜线,单引号,双引号,再加一个反斜线。在文本中含有
javascript字符串的时候有用。
date :用来对data和datatime对象的字符串信息进行格式化。
{{ pub_date|date:"F j, Y" }}
length :返回变量的长度。
在view中使用template:
首先在settings.py中配置模板文件的路径。
TEMPLATE_DIRS = (
'/home/django/mysite/templates',
)
记住一个路径的时候要使用逗号,这样是来区分是一个tuple还是一个block expression
也可以在设置的时候使用python文件路径操作代码:
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)
然后,可以在view中使用模板
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)
大多数情况下,你会使用一种shortcut方法,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})
locals()的小技巧
如果你有很多变量要传给render,一个一个构造dict元素很麻烦。直接把变量名改成模板中所需要的变量名,
再使用locasl()函数,轻松搞定
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response('current_datetime.html', locals())
locals()会返回局部空间中变量信息的dict,直接可以传给render,但有一点需要注意,它会返回把有的局部变量
信息,有一些可能不需要用到,如request变量。
{%
include%}的使用
{% include 'nav.html' %},用来引入其它模板的内容,减少重复的模板代码
{% include template_name %},还可以使用变量名
如果include的模板文件没有找到,当DEBUG为真时,会报错TemplateDoesNotExist,当为假时,页面那一块为
空白。
诚然,include可以有效减少模板的重复代码。但一种更优雅的方式是:
template inheritance.
首先,创建base.html
- {% block content %}{% endblock %}
- {% block footer %}
- {% endblock %}
- 我们使用一个新的tag,{% block %}用来告诉template engine,这个部分会被子模板
- 来实现。如果子模板没有实现这些部分,就会默认使用父模板的代码。
- 再看看,子模板要怎么写:
- {% extends "base.html" %}
- {% block title %}The current time{% endblock %}
- {% block content %}
- {% endblock %}
- 只需要先使用{% extends %}继承父模板,再把相应需要实现的部分写上所需要的内容。
- {% extends template_name %}也可以使用变量名来实现动态。
- 模板继承的三层继承策略:
- 1. 创建一个base.html,用来设置外观
- 2. 为网站的每一个部分,创建base_SECTION.html,比如base_phote.html, base_forum.html
- 3. 为每一个页面创建自己的模板。
- 首先,我们回顾模板的视图函数如何书写:
- from django.shortcuts import render_to_response
- def diary(request):
- return render_to_response('diary.html', {'name': 'qiqi'})
- 为了说明方便,我们同时给出另一种写法:
Here are the athletes: {{ athlete_list }}.
No athletes are available.
Here are the coaches: {{ coach_list }}.
There are no athletes. Only computer programmers.
{{ forloop.counter }}: {{ item }}
Country #{{ forloop.parentloop.counter }} | City #{{ forloop.counter }} | {{ city }} |
Welcome!
Community
My helpful timestamp site
Thanks for visiting my site.
It is now {{ current_date }}.
Django框架模板高级进阶
1. RequestContext函数和context处理器
from django.http import HttpResponse from django.template import loader, Context def diary(request): t = loader.get_template('diary.html') c = Context({'name': 'qiqi'}) return HttpResponse(t.render(c))
或许还是有同学看不懂,那我就再给出第三种最笨的等价写法,大家大可略过直接往后看:
from django.http import HttpResponse from django.template import Template, Context def diary(request): tin = open('./templates/diary.html') html = tin.read() tin.close() inf = {'name': 'qiqi'} t = Template(html) c = Context(inf) return HttpResponse(t.render(c))
在上述代码中,我们是用Context函数进行渲染的。
而与django.template.Context函数差不多的,还有一个django.template.RequestContext函数,它默认在模板中加了一些变量,比如HttpRequest对象、当前登录用户的相关信息……
来看下面这段代码:
from django.http import HttpResponse from django.template import loader, Context def view_1(request): # ... t = loader.get_template('template1.html') c = Context({ 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'], 'message': 'I am view 1.' }) return HttpResponse(t.render(c)) def view_2(request): # ... t = loader.get_template('template2.html') c = Context({ 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'], 'message': 'I am the second view.' }) return HttpResponse(t.render(c))
其中app、user、ip_address这三个变量,可能需要在很多模板的渲染中重复写入,很麻烦。而利用RequestContext函数,我们便可以将之简化为这样:
from django.http import HttpResponse from django.template import loader, RequestContext def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] } def view_1(request): # ... t = loader.get_template('template1.html') c = RequestContext(request, {'message': 'I am view 1.'}, [custom_proc]) return HttpResponse(t.render(c)) def view_2(request): # ... t = loader.get_template('template2.html') c = RequestContext(request, {'message': 'I am the second view.'}, [custom_proc]) return HttpResponse(t.render(c))
其中,我们写的函数custom_proc,便称为context处理器。用术语来说,我们利用RequestContext函数和context处理器,简化了使用模板的代码。
而在此基础上使用render_to_response,我们还可以将之简化成:
from django.shortcuts import render_to_response from django.template import RequestContext def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] } def view_1(request): # ... return render_to_response('template1.html', {'message': 'I am view 1.'}, context_instance=RequestContext(request, [custom_proc])) def view_2(request): # ... return render_to_response('template2.html', {'message': 'I am the second view.'}, context_instance=RequestContext(request, [custom_proc]))
此时,还是有一点美中不足的――渲染语句中,每次都需要手动为processors赋值。
Django提供了对全局context处理器的支持――可以让你在全局变量中列出一些context处理器,Django在你每次调用RequestContext函数时都会自动加入这些处理器的。这个全局变量在TEMPLATES参数中可以找到,其默认值是:
# TEMPLATES参数中,'OPTIONS'字典中的,'context_processors'列表 [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ]
这四个值不多说,可以去查书和手册。此时,我们可以进一步简化代码如下:
from django.shortcuts import render_to_response from django.template import RequestContext def view_1(request): # ... return render_to_response('template1.html', {'message': 'I am view 1.'}, context_instance=RequestContext(request)) def view_2(request): # ... return render_to_response('template2.html', {'message': 'I am the second view.'}, context_instance=RequestContext(request))
至于context处理器,则应当写在单独的一份代码中,推荐命名为context_processors.py。
只要把这份代码放在Python搜索路径中,Django就可以找到。推荐把它放在project或者app的目录下。
# context_processors.py def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] }
最后,修改全局变量即可:
[
'context_processors.custom_proc',
]
2. html自动转义
从模板生成html时,总会有一个风险――变量包含了会影响html的字符。
书中举了小例子,这里不加赘述,直接说解决方法:
1. 确保每个不被信任的变量都用escape过滤器过滤一遍,把潜在的有害html字符转换为无害的。这是初几年Django的处理策略。
2. 利用Django的html自动转义。下面介绍这种方法。
只要你使用Django模板,那么变量标签中的以下五个字符都会被自动转义:
原字符 转义结果
< <
> >
' '
" "
& &
当然,有时候你会自己手动用模板变量写一段html代码,那这时候你就需要关闭自动转义了,关闭方法如下:
1. 变量级别,用safe过滤器: This will not be escaped: {{ data|safe }}
2. 模板级别,用autoescape标签: {% autoescape off %} ... {% endautoescape %}
这个标签有两种状态:off、on。
这个标签是可以嵌套的,例如你可以在一个off的标签内嵌套on的标签。
当你使用模板继承的时候,显而易见,这个标签依旧会持续生效的。
3. 站点级别,这个书中只说有方法,却没写,暂时存疑。
注意:
1. 过滤多次和过滤一次效果完全一样。
2. 模板中的字符串常量(例如过滤器中包含的常量)会逃过自动转义,而变量中的字符串则不会。
{{ data|default:"3 < 2" }}
{{ data|default:"3 < 2" }} <-- Bad! Don't do this.
存疑:
1. escape过滤器是什么?根据文档中所写,好像是专指autoescape标签?
3. Django如何加载模板
3.1 什么是Engine
Engine,简单来说就是关于模板的一份设置,具体定义这里暂不介绍,大家可以先去文章开头所给的文档中查看,以后有时间会补上。
平时加载模板,使用的就是Django中默认的一个Engine对象,其内容就是咱们在settings.py中那个TEMPLATES参数。因此,你用默认的方式加载模板,也就等同于你用Django中这个默认的Engine对象来加载模板。这个对象是: django.template.engines['django']
而如果你想要实例化另一个Engine对象,则需要用这个定义: django.template.Engine()
3.2 加载模板的语句
Django加载模板的语句有三种:
1. Engine.from_string(template_code)
按照Engine对象的设置,编译所给代码生成模板,返回一个Template对象。
# 方法一,使用默认的Engine
from django.template import engines
template = engines['django'].from_string(template_code)
# 方法二,使用一个空的Engine(没有context_processors之类的东西)
from django.template import Engine
template = Engine().from_string(template_code)
2. Engine.get_template(template_name)
按照Engine对象的设置,根据所给名称找到模板,在内部进行编译,最后返回一个Template对象。
如果模板不存在,则返回一个TemplateDoesNotExist的异常。
3. Engine.select_template(self, template_name_list)
按照Engine对象的设置,根据所给列表中的名称,顺次寻找模板,把找到的第一个同样处理,返回一个Template对象。
如果全都不存在,则返回一个TemplateDoesNoeExist的异常。
3.3 模板加载器
我们一直说在加载模板,但是TEMPLATES参数中却并没有加载器的设置,此时我们所用的一直是Django中默认的加载器。
下面,我们就一一介绍Django中的模板加载器:
1. django.template.loaders.filesystem.Loader(默认)
从文件系统中加载模板。
路径:TEMPLATE参数中'DIRS'列表。
2. django.template.loaders.app_directories.Loader
从文件系统中加载模板。
路径:各app,即INSTALLED_APPS参数每个app目录下的templates文件夹。
开启方式:将TEMPLATES参数中'APP_DIRS'设置为True。
3. django.template.loaders.eggs.Loader
从Python egg中加载模板。
路径:各app。
开启方式:写出类似代码(未经测试,仅供参考)――
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'OPTIONS': { 'loaders': [ ('django.template.loaders.eggs.Loader'), ], }, }]
4. django.template.loaders.cached.Loader
加载模板时,第一次调用各加载器加载模板并存入缓存,以后则从缓存中直接加载模板。
路径:取决于调用的各加载器。
注意:实际加载的各模板应该保证其结点(Node)是进程安全(thread-safe)的,详见文档。
开启方式:写出类似代码(源自文档)――
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'OPTIONS': { 'loaders': [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), ], }, }]
5. django.template.loaders.locmem.Loader
从Python字典中加载模板,常用于测试。
存疑:实际效果未测试过,不是很能理解。
开启方式:写出类似代码(源自文档)――
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ('django.template.loaders.locmem.Loader', { 'index.html': 'content here', }), ], }, }]
实际上,书和文档中还提到了如何写自己的模板、模板中用于debug的两个类、如何写独立模型下的模板……
但由于暂时还用不到,所以先不写了,等以后用到再补充。
相关文章
- PHP导出数据超时的优化建议解读 10-31
- PHP之mysql位运算解析 10-31
- Laravel实现登录跳转功能解析 10-31
- php双向队列解读 10-31
- Laravel异常上下文解决教程 10-24
- php数组查询元素位置方法介绍 10-24