模板
1、视图中使用模板
模版的创建过程,对于模版,其实就是读取模版(其中嵌套着模版标签),然后将 Model 中获取的数据插入到模版中,最后将信息返回给用户
1.普通方法:HTML被直接硬编码在 Python 代码
def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
尽管这种技术便于解释视图是如何工作的,但直接将HTML硬编码到你的视图里却并不是一个好主意,我们应该将页面的设计和Python的代码分离开会更干净简洁更容易维护。这时,我们可以使用 Django的 模板系统 (Template System)来实现这种模式
2.Django 模版基本语法
1、创建模板:
一旦你创建一个 Template 对象,你可以用 context 来传递数据给它。 一个context是一系列变量和它们值的集合
from django import template t = template.Template('My name is {{ name }}.')#创建Template 对象 c = template.Context({'name': 'SunshineBoy'}) #创建一个 Context 对象 print(t.render(c))
>>>u'My name is SunshineBoy'
#另外同一模板,可以有多个上下文,即可以同一模板渲染多个context
#context在Django里表现为 Context 类,在 django.template 模块里。 她的构造函数带有一个可选的参数: 一个字典映射变量和它们的值。 调用 Template 对象 的 render() 方法并传递context来填充模板
ps:我们可以使用同一模板源渲染多个context,只进行 一次模板创建然后多次调用render()方法渲染会更为高效
注意:t.render(c)返回的值是一个Unicode对象,不是普通的Python字符串。 你可以通过字符串前的u来区分。 在框架中,Django会一直使用Unicode对象而不是普通的字符串
Template加载
import datetime from django import template import DjangoDemo.settings now = datetime.datetime.now() fp = open(settings.BASE_DIR+'/templates/Home/Index.html') t = template.Template(fp.read()) fp.close() html = t.render(template.Context({'current_date': now})) return HttpResponse(html)
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)
TEMPLATE_LOADERS = ( #'django_mobile.loader.Loader', 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', #'django.template.loaders.eggs.Loader', )
以上这些均是底层如何载入一个模板文件,然后用 Context渲染它,最后返回这个处理好的HttpResponse对象给用户。 我们已经优化了方案,使用 get_template() 方法代替繁杂的用代码来处理模板及其路径的工作。 但这仍然需要一定量的时间来敲出这些简化的代码。 这是一个普遍存在的重复苦力劳动。
Django为此提供了一个捷径,让你一次性地载入某个模板文件,渲染它,然后将此作为 HttpResponse返回。
该捷径就是位于 django.shortcuts 模块中名为 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})
2、深度变量的查找
前面,我们通过 context 传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。
在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。
如:假设你要向模板传递一个 Python 字典。 要通过字典键访问该字典的值,可使用一个句点(.)
from django.template import Template, Context person = {'name': 'Lily', 'age': '22'} t = Template('{{ person.name }} is {{ person.age }} years old.') c = Context({'person': person}) print(t.render(c)) >>>u'Lily is 22 years old.'
同样,也可以通过句点来访问对象的属性。 比方说, Python 的 datetime.date 对象有 year 、 month 和 day 几个属性,你同样可以在模板中使用句点来访问这些属性:
>>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1995, 5, 20) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') >>> c = Context({'date': d}) >>> t.render(c) u'The month is 5 and the year is 1995.'
同样,我们自定义类的实例对象也可以通过(.)来访问其实例属性
>>> from django.template import Template, 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')}) >>> t.render(c) u'Hello, John Smith.'
点语法也可以用来引用对象的* 方法*。 例如,每个 Python 字符串都有 upper() 和 isdigit() 方法
>>> 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'
ps:注意这里调用方法时并* 没有* 使用圆括号 而且也无法给该方法传递参数;你只能调用不需参数的方法
最后,句点也可用于访问列表索引,例如
>>> 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.'
3、模版语言
模板中也有自己的语言,该语言可以实现数据展示#引用变量
{{ item }} #引用标签(tag) {% for item in item_list %} <a>{{ item }}</a> {% endfor %} forloop.counter #一个表示当前循环的执行次数的整数计数器。 这个计数器是从1开始的,所以在第一次循环时 forloop.counter 将会被设置为1,forloop.counter0 它是从0计数的 forloop.first #是否是循环的第一个 ,布尔值 forloop.last #是否是循环的最后一个 ,布尔值 {% if ordered_warranty %} {% else %} {% endif %} #继承 母板:{% block title %}{% endblock %} 子板:{% extends "base.html" %} {% block title %}{% endblock %} #过滤器: {{ item.event_start|date:"Y-m-d H:i:s"}} #时间格式化 {{ bio|truncatewords:"n" }} #对字符串进行截段,,取这个模板变量的前 N 个字符,只能用于英文 {{ bio|slice:"n" }} #取变量前 N 个字符,可用于中文 {{ my_list|first|upper }} {{ name|lower }} {{ value|default:"nothing" }} #如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值
# Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义 {{ value|safe}} #通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义
4、 用simple_tag 来自定义模板方法
a、在app中创建templatetags模块
b、创建任意 .py 文件,如:xx.py
#!/usr/bin/env python #coding:utf-8 from django import template from django.utils.safestring import mark_safe register = template.Library() #只能是register不能改为其它 @register.simple_tag def my_simple_time(v1,v2,v3): return v1 + v2 + v3 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result) #使用方法函数mark_safe ,使用mark_safe函数标记后,django将不再对该函数的内容进行转义.因为django默认会自动转义模板中的内容,把标签转换为相应的HTML实体。这样可以防止后端为数据库的网站被恶意脚本攻击
c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% my_simple_time 1 2 3%} {% my_input 'id_username' 'hide'%}
e、在settings中配置当前app,不然django无法找到自定义的simple_tag
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', )