django-templates
模板内容总结:
1.基础
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context({'name': 'Adrian'})
>>> print t.render(c)
>>> 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.'
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
u'hello -- HELLO -- False'
... silent_variable_failure = True
>>> class PersonClass4:
... def first_name(self):
... raise SilentAssertionError
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
u'My name is .'
基本的tag和filter的用法
tag:
- {% if %}的使用
- {% for %} 的使用
- ifequal和ifnotequal,一看就是直接比较值的tag,需要两个参数,用法比较有限,
- 只限于字符串,整数,小数的比较,什么列表,字典,元组不支持。
- {# #},模板中注释的用法,只能用在一行
- 如果要使用多行注释,要使用{% comment %}
filter:
- addslashes :给任何的反斜线,单引号,双引号,再加一个反斜线。在文本中含有javascript字符串的时候有用。
- date :用来对data和datatime对象的字符串信息进行格式化。
- {{ pub_date|date:"F j, Y" }}
- length :返回变量的长度。
在view中使用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)
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('current_datetime.html', {'current_date': now})
模板渲染
一旦你创建一个 Template 对象,你可以用 context 来传递数据给它。 一个context是一系列变量和它们值的集合。
context在Django里表现为 Context 类,在 django.template 模块里。 她的构造函数带有一个可选的参数: 一个字典映射变量和它们的值。
current_date = datetime.datetime.now()
return render_to_response('current_datetime.html', locals())
#base.html
<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link type="text/css" rel="stylesheet" href="/static/css/base.css"/>
<title>{%block title %} {%endblock%}</title>
<body>
<h1>后台管理</h1><p class="path"> 当前位置:{%block path%}{%endblock%} <span>欢迎你:{{admin}} <a href="#">注销</a></span></p> {%block content%}{%endblock%} </body>
</html>
#piclist.html
{%extends "base.html"%} {%block title %}图片列表页面{%endblock%} {%block path%}图片列表{%endblock%} {%block content%} 内容 {%endblock%}
1.模板的简单使用:
t = template.Template('My name is {{ name }}.')
c = template.Context({'name':'nick'})
print t.render(c)
创建一个Template对象,实例化。默认构造参数 直接接受字符串作为模板内容。
其中{{}}表示模板的变量。
一旦你创建了Template模板实例,你可以用Context来传递参数给它。
格式 Context({'name':'nick'}) 第一个参数为模板变量的映射,第二个为要传递的值。并以 “:”分开,如果是多个集合用“,”分隔。
最后调用Template对象的 render()方法,并用context对象来填充模板。
同一个模板对象,可对应多个上下文对象。
如果遍历一个结构对象,可以使用如下方法。
person = {'name':'sally','age':'43'}
t = Template('{{ person.name }} is {{ person.age }} years old.')
c = Context({'person':person})
t.render(c)
在模板的方法调用中,有一个操作流程是需要注意的。
在查找方法的过程中,如果方法抛出了一个异常,除非该异常有一个silent_variable_failure属性,别且值为true,否则它将继续传播。
举例:例如你有一个 BankAccount 对象,有一个Del()方法。
如果某个模板包含了 {{ account.del }} 的标签,account是BankAccount的一个实例。这个模板载入时,account对象被删除。
防止这样的事情发生,必须设置 alters_data函数.
Del.alters_data = True
模板不会执行任何以该方式进行标记的方法。
模板中得注释,使用 {# 注释内容 #} 该注释不能跨行。
如果跨行,需要使用模板标记
注释内容
=====================================================================================
2.在视图中使用模板
模板加载机制
打开settings.py文件,找到TEMPLATE_DIRS这项设置。
添加一个用于存放模板的路径,如下:
如果考虑到以后部署等问题,可以使用动态的路径方法如:
TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'), )
设置好模板路径后
在项目路径下,创建文件夹 templates
1.在文件下创建一个HTML页面文件template1.html,内容如下:
2.然后创建一个 视图函数 代码如下
from django.template.loader import get_template
import datetime
def current_datetime(request):
now = datetime.datetime.now()
t = get_template('template1.html')
c = Context({'nowtime':now})
html = t.render(c)
return HttpResponse(html)
运行SERVER,看效果吧。
再记录个 简化模板处理的方法。
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('template1.html',{'nowtime':now})
========================================================================================
include 模板标签
{% include %} 允许在模板中包含其它模板的内容。
标签的参数可以是:模板名称 、变量、字符串。
{% include 'nav.html' %}
{% include 'includes/nav.html' %}
{% include template_name %}
模板继承
本质上说:模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点共用部分和定义进行重载。
创建 base.html模板:
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>我得时间表</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>谢谢对网站的支持</p>
{% endblock %}
</body>
</html>
创建子模板 test.html
{% block title %}现在时间{% endblock %}
{% block content %}
<p>现在时间是:{{nowtime}}</p>
{% endblock %}
省略 视图函数。
因为子模板没有定义 footer 块。所以使用父模板中定义的值。
你可以根据需要使用任意多的继承次数,使用继承的一种常见方式如下三层法则。
1. 创建base.html模板,在其中定义站点的主要外观感受。这些都是不常修改甚至从不修改的内容。
2. 为网站的每个区域创建 base_SECTION.html模板(例如,base_photos.html和base_forum.html) 。
这些模板对base.html进行拓展,并包含区域特定的风格与设计。
3. 为每种类型的页面创建独立的模板,例如论坛页或图片库。这些模板扩展相应的区域模板。
使用模板的一些诀窍
- 如果在模板中使用{% extends %},必须保持其为模板中的第一个模板标记。否则,模板继承将不起作用。
- 一般来说,基础模板中得{% block %}标签越多越好。子模板不必定义父模板中所有的代码块,因此你可以
合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行重载。 - 如果发现自己在多个模板之间拷贝代码,你应该考虑将该代码放置到父模板的某个 {% block %}中。
- 如果你需要访问父模板中块的内容,使用{{ block.super }}这个标签。
- 主要不要在同一个模板中定义同名的{% block %}.
- {% extends %}对所传入模板名称使用的加载方法和get_template()相同。
- 多数情况下,{% extends %}的参数应该是字符串,但如果想实现动态的父模板名,这个参数可以是变量。
复习一下模板语言的用法
使用RequestContext对上下文内容进行重用
1. Context版
from django.http import HttpResponse
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))
from django.http import HttpResponse
# 使用context processro去提供一些context内容中公共的部分,也就是返回一个字典而已。
def custom_proc(request):
"A context processor that provides 'app', 'user' and 'ip_address'."
return {
'app': 'My app',
'user': request.user,
'ip_address': request.META['REMOTE_ADDR']
}
def view_1(request):
# ...
t = loader.get_template('template1.html')
# 创建方式不同,需要提供的参数有三个,request对象,字典类型,processors可选
c = RequestContext(request, {'message': 'I am view 1.'},
processors=[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.'},
processors=[custom_proc])
return HttpResponse(t.render(c))
{'message': 'I am the second view.'},
context_instance=RequestContext(request, processors=[custom_proc]))
当使用模板生成HTML代码时,如果变量内容是一些影响HTML结果的字符时,那就挺危险的。
> 被转义成 >
' 被转义成 '
" 被转义成 "
& 被转义成 &
如何关闭这个功能?
对于filter过滤器中参数的自动转义
创建模板库
实现自定义过滤器
1. 创建register变量
register = template.Library()
2. 定义过滤器函数
#移除字符串中var的arg字串
return var.replace(arg, '')
"Converts a string into all lowercase"
return value.lower()
3. 注册过滤器函数
#第二个就是你的过滤器函数引用名
register.filter('remove', remove)
register.filter('lower', lower)
def remove(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
register = template.Library()
@register.filter(name='remove')
def remove(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
实现自定义tag
了解模板编译过程
{% ifequal name.birthday today %}
Happy birthday!
{% else %}
Be sure to come back on your birthday
for a splendid surprise message.
{% endifequal %}
- Text node: "Hello, "
- Variable node: person.name
- Text node: ".\n\n"
- IfEqual node: name.birthday and today
创建tag实战
1. 定义Node节点类,实现render方法
from django import template
#这一句还是要的
register = template.Library()
class CurrentTimeNode(template.Node):
def __init__(self, format_string):
self.format_string = str(format_string)
def render(self, context):
now = datetime.datetime.now()
#返回的是格式化后的时间表示字符串
return now.strftime(self.format_string)
2. 创建Compilation函数
try:
tag_name, format_string = token.split_contents()
except ValueError:
msg = '%r tag requires a single argument' % token.split_contents()[0]
raise template.TemplateSyntaxError(msg)
return CurrentTimeNode(format_string[1:-1])
3. 注册tag
def do_current_time(parser, token):
# ...
@register.tag
def shout(parser, token):
# ...
import datetime
register = template.Library()
@register.filter(name='remove')
def remove(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
class CurrentTimeNode(template.Node):
def __init__(self, format_string):
self.format_string = str(format_string)
def render(self, context):
now = datetime.datetime.now()
return now.strftime(self.format_string)
def do_current_time(parser, token):
try:
tag_name, format_string = token.split_contents()
except ValueError:
msg = '%r tag requires a single argument' % token.split_contents()[0]
raise template.TemplateSyntaxError(msg)
return CurrentTimeNode(format_string[1:-1])
register.tag('current_time', do_current_time)
4. 运行
复杂的实现自定义tag的其他几种方法
1. 在Node类的render函数中设置context
now = datetime.datetime.now()
#设置context对象的值
context['current_time'] = now.strftime(self.format_string)
# render函数一定要返回字符串,即使是空串
return ''
<p>The time is {{ current_time }}.</p>
<p>The current time is {{ my_current_time }}.</p>
class CurrentTimeNode3(template.Node):
def __init__(self, format_string, var_name):
#增加自定义变量名的参数
self.format_string = str(format_string)
self.var_name = var_name
def render(self, context):
now = datetime.datetime.now()
context[self.var_name] = now.strftime(self.format_string)
return ''
def do_current_time(parser, token):
#使用正规表达式来处理token
try:
# 使用string.split(sep[, maxsplit]),1代表最大分割数,也就是
# 分割后会产生maxsplit+1个元素
# 这里分割后的结果为(get_current_time, '"%Y-%M-%d %I:%M %p" as my_current_time')
tag_name, arg = token.contents.split(None, 1)
except ValueError:
msg = '%r tag requires arguments' % token.contents.split_contents()[0]
raise template.TemplateSyntaxError(msg)
#使用()代表正则组,匹配as两边的字符串
m = re.search(r'(.*?) as (\w+)', arg)
if m:
fmt, var_name = m.groups()
else:
msg = '%r tag had invalid arguments' % tag_name
raise template.TemplateSyntaxError(msg)
#如果格式没被引号引用,报错
if not (fmt[0] == fmt[-1] and fmt[0] in ('"', "'")):
msg = "%r tag's argument should be in quotes" % tag_name
raise template.TemplateSyntaxError(msg)
# [1:-1]去除格式两边的引号
return CurrentTimeNode3(fmt[1:-1], var_name)
register.tag('get_current_time', do_current_time)
2. 实现块作用区域的tag
nodelist = parser.parse(('endcomment',))
parser.delete_first_token()
return CommentNode()
class CommentNode(template.Node):
def render(self, context):
return ''
3. 在块作用tag中保留context内容
This will appear in uppercase, {{ user_name }}.
{% endupper %}
nodelist = parser.parse(('endupper',))
parser.delete_first_token()
return UpperNode(nodelist)
class UpperNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
output = self.nodelist.render(context)
return output.upper()
4. 快速创建简单tag的方法
try:
return datetime.datetime.now().strftime(str(format_string))
except UnicodeEncodeError:
return ''
register.simple_tag(current_time)
def current_time(token):
# ...
5. 创建Inclusion Tag
<li>The Cat In The Hat</li>
<li>Hop On Pop</li>
<li>Green Eggs And Ham</li>
</ul>
- 定义函数
books = Book.objects.filter(authors__id=author.id)
return {'books': books}
- 创建另一个模板文件book_snippet.html
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
- 注册tag
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
创建自定义模板加载类
from django.template import TemplateDoesNotExist
import zipfile
def load_template_source(template_name, template_dirs=None):
"Template loader that loads templates from a ZIP file."
#从settings.py配置文件中读取属性TEMPLATE_ZIP_FILES的值,默认返回空列表
template_zipfiles = getattr(settings, "TEMPLATE_ZIP_FILES", [])
# Try each ZIP file in TEMPLATE_ZIP_FILES.
for fname in template_zipfiles:
try:
z = zipfile.ZipFile(fname)
source = z.read(template_name)
except (IOError, KeyError):
continue
z.close()
# 找到一个可用的文件就返回
template_path = "%s:%s" % (fname, template_name)
return (source, template_path)
# 如果一个zip文件没找到,报错
raise TemplateDoesNotExist(template_name)
# 设置为可用
load_template_source.is_usable = True
'books.zip_loader.load_template_source',
)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)