配置

(1)最常见的放置自定义Tag和Filter的地方是在Django的app下。当一个app被添加到settings.py的INSTALLED_APPS 后,任何在它下面的合法位置将自动的可在templates中被调用。合法位置就是在app下的templatetags子文件夹下,但不要忘记添加init.py文件来表明它是个包。

自定义的tag或者filter就在templatetag文件夹下的py文件中,在template中调用的是该py文件的名字,比如

app名字是polls,tags/filter在poll_extras.py中:

polls/
__init__.py
models.py
templatetags/
__init__.py
poll_extras.py
views.py

在template中这样加载定义在poll_extras.py中的tags/filters:

{% load poll_extras %}

包含定制的tags/filters的app必须在INSTALLED_APPS,并且{% load ... %}也是在INSTALLED_APPS从上往下搜索。

(2)当然放置Tag和Filter的文件也不一定非得在app中,可以在project的任何地方,但是这种情况下,需要在DjangoTemplateslibraries中注册,比如,将放置tag/filters的文件testcommon.py放置在工程的新建common文件夹下。

然后在settings.py的TEMPLATE中注册该文件,需要注意的是在templates中load的是‘commonfile'。

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [TEMPLATE_DIR],
'APP_DIRS': True,
'OPTIONS': {
# 'string_if_invalid':InvalidTemplateVariable('%s'),
# 'autoescape':False,
'context_processors': [ 'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'banners.processors.onsale', ],
'libraries':{'commonfile':'testBegin.common.testcommon'},
},
},
]

testcommon.py中定义commonfilter:

from django import template
from django.utils.html import escape
from django.utils.safestring import mark_safe
register=template.Library()
@register.filter(needs_autoescape=True)
def commonfilter(value,autoescape=True):
if autoescape:
value=escape(value)
result='<b>%s</b>'%value
return mark_safe(result)

最后在template中调用:

{% load commonfile %}
{{ coffee|commonfilter }} #其中coffee变量为'mocamoca'

那能不能像built-in filter一样,不用每次都声明{% load custom filter %}?可以的,只需要在settings.py中的'TEMPLATES'的'OPTIONS'字段内加入'builtins':['location of files containing filter'],比如:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [TEMPLATE_DIR],
'APP_DIRS': True,
'OPTIONS': {
# 'string_if_invalid':InvalidTemplateVariable('%s'),
# 'autoescape':False,
'context_processors': [ 'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'banners.processors.onsale', ],
'builtins':['testBegin.common.testcommon'],
},
},
]

写自定义的模板filter

自定义filter是有1个或者2个参数的Python函数:

  • 输入变量的值(不一定必须是string)

  • 值的参数,可以有默认值

    比如,{{ var|foo:'bar' }},foo被掺入了变量var和参数'bar'。

    下面是个简单的例子:

    #bannerTags.py
    from django import template
    register=template.Library() @register.filter()
    def john(value,arg):
    return value.replace(arg,'john')
    {% load bannerTags %}
    {{ coffee|john:'m' }}

    coffee的值为'macomaco',

@register.filter可以没有参数,直接用@register.filter来装饰,也可以有参数,起到特定的功能:

  • name:默认的filter的名字就是函数名字,而name参数可以改变filter的名字

@register.filter(name='cutname')
def cut(value, arg):
return value.replace(arg, '')
{{ coffee|cutname:'m' }}
  • 此外,还有is_safe,needs_autoscape,expects_localtime.

字符期望的Filter(Template filters that expect strings)

django.template.defaultfilters.stringfilter()

在上面的例子中,如果coffee的值是11,则会报错:

解决这个只需要再加层装饰器就可以了:

from django import template
from django.template.defaultfilters import stringfilter
register=template.Library()
@register.filter
@stringfilter
def john(value,arg):
return value.replace(arg,'john')

可以发现已经没有报错了:

Filter 和 auto-escaping

from django import template
from django.template.defaultfilters import stringfilter
register=template.Library()
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe @register.filter
@stringfilter
def john(value,arg):
return value.replace(arg,'john')
@register.filter(is_safe=True)
def myfilter0(value):
return value
@register.filter()
def myfilter(value):
return mark_safe(value) @register.filter(needs_autoescape=True)
def testautoes(text,autoescape=True):
first,other=text[0],text[1:]
if autoescape:
esc=conditional_escape
else:
esc=lambda x:x
result='<b>%s</b>%s' % (esc(first),esc(other))
return mark_safe(result)
# return result @register.filter()
def myfilter1(value):
value=conditional_escape(value)
return mark_safe(value) @register.filter()
def myfilter2(value):
value=conditional_escape(value)
return value @register.filter()
def myfilter3(value):
return value
{% load bannerTags %}
{{ coffee|john:'a' }}
<br>
{{ coffee|testautoes }}--testautoes
<br>
{{ coffee|myfilter }}--myfilter
<br>
{{ coffee|myfilter0 }}--myfilter0
<br>
{{ coffee|myfilter1 }}--myfilter1
<br>
{{ coffee|myfilter2 }}--myfilter2
<br>
{{ coffee|myfilter3 }}--myfilter3

当在settings.py的Templates的'OPTIONS'添加autoexcape:False时,

从这个例子可以看出几点:

  • 自定义filter的函数大多都受总的autoescape设定(即settings.py中关于autoescape)的影响,如果总的autoescape被设定为False,则含有”不安全“的符号如'<,>,'将不被转义,但是当通过conditional_escape处理后,则仍然被转义,具体表现为上图'myfilter1'和'myfilter2'
  • 当总的autoescape是True(默认情况),大多含有”不安全“的符号,都要进行转义,但是通过mark_safe而没有通过conditional_escape的处理,将直接被渲染。

写自定义Tags

Tags 比Filter更复杂,因为tags可以做任何事情,Django提供了很多快捷方式来使得写tags更方便。

Simple tags

django.template.Library.simple_tag()

很多模板tag有很多参数,字符串或者模板变量,然后仅仅基于输入的参数进行一些操作,然后返回结果。比如,‘current_time'可以接受一个字符串模板,返回时间的格式化的字符。

为了简化这种tag的创建过程,Django提供了个帮助函数,simple_tag,这个函数是django.template.Library的方法,它的接受任意的参数,用render函数包裹该函数,所以它就是起了一个装饰器的作用。

#bannerTags.py
import datetime
from django import template register = template.Library() @register.simple_tag
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
{% load bannerTags %}
{% current_time ' %Y/ %m/ %d' as tim %}
{{tim}}

不像其他tag的用法,如果是autoescape模式,simple_tag就会将它的输出再输入conditional_escape()中,来保证正确的HTML,来免于XSS攻击。

如果十分确定没有XSS攻击代码,则可以用mark_safe(),而对于创建小的HTML代码块,建议用format_html(),而不是mark_safe().

  • 如果需要重命名,老规矩,就像Filter一样,在register.simple_tag()中传入name即可。

  • 如果需要接受任意数量的positional argument或者keyword arguments,比如:

    @register.simple_tag
    def my_tag(a, b, *args, **kwargs):
    warning = kwargs['warning']
    profile = kwargs['profile']
    ...
    return ...

    在模板中,任意的参数,被空格分隔,就会被传入tag中。与python类似的是,对于keyword argument,用 等于号 '='来表示,而keyword argument跟在python中的类似,也必须放在position arguments之后。

    {% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
  • 如果不直接输出tag的结果,而是将该结果储存起来,也是可以的。通过as就可以达到这个效果,比如:

    {% current_time "%Y-%m-%d %I:%M %p" as the_time %}
    <p>The time is {{ the_time }}.</p>

    Inclusion tags

    django.template.Library.inclusion_tag()

    另一种常见的类型是通过render其他的模板来展示数据的,这种tags被称为'inclusion tags‘。

写法步骤如下:

(1)首先定义一个函数及其输入参数,然后返回一个字典,该字典将被当做一个template context传入被rendered 的其他模板。

#testcommon.py
def show_results(strings):
choices=strings.split('s')
return {'choices':choices}

(2)定义被rendered的其他模板,其位置必须能被搜索到。

# results.html
<ul>
{% for alpha in choices %}
{% if alpha %}
<li> {{ alpha }}</li>
{% endif %}
{% endfor %}
</ul>

(3)通过调用inclusion_tag来创建,和注册一个inclusion tag。

#testcommon.py
@register.inclusion_tag('banners/results.html')
def show_results(strings):
choices=strings.split('s')
return {'choices':choices}

(4)在模板中使用该tag。

#test.html
{% show_results coffee %}

其路由为:

urlpatterns=[
url(r'^method',views.method,name='method'),
url(r'^$',TemplateView.as_view(template_name='banners/test.html',extra_context={'coffee':'moscamsocas'}),name='index'),
]

运行:

  • 也可以在模板中直接传字符串:

    #test.html
    {% show_results 'asbscs' %}

还有一种等效的方法是:

#testcommon.py
from django.template.loader import get_template
t=get_template('banners/results.html')
register.inclusion_tag(t)(show_results)

可以看到,本质上与第一种方法是一样的,只不过是显式的找到html然后传递给register.inclusion_tag,然后再传入show_results,这个过程本身就是装饰器的显式表达。

有时候,inclusion tags需要将大量的参数传入,这时候对于使用tags的人来说非常痛苦,还要记住参数顺序。为解决这种问题,Django为inclusion tag提供了take_context选项,当表明了它,并设置为True,使用模板时,可以不需要参数,相应的python function只需要传入一个参数context,从而达到直接将被调用的template的context_dict传入tag function,并通过tag function 传入被rendered的Html。

比如:

@register.inclusion_tag('banners/results.html',takes_context=True)
def show_results(context):
choices=context['coffee'].split('s')
return {'coffee':choices }
#被call的test.html
{% show_results %}
#被rendered的html,可见coffee被传入
<ul>
{% for alpha in coffee %}
{% if alpha %}
<li> {{ alpha }}</li>
{% endif %}
{% endfor %}
</ul>

最后,inclusion_tag也可以接受任意数量的position argument和keyword argument:

如:

@register.inclusion_tag('my_template.html')
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
...
return ...
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}

定制Django的Tag和Filter(二)的更多相关文章

  1. Django之tag标签和filter标签

    1.Django的tag常见的标签,可以做一些简单的功能 {%if%} 的使用主要用于做判断,还可以包含{%elif%} 这样的用法,最后要跟上{% endif %}.可以使用你的and,or,not ...

  2. Django(模板语言-自定义filter和simple_tag)

    Django(模板语言-自定义filter和simple_tag)   filter过滤器的主要形式:变量|函数,意思是将变量交给函数处理,而自定义filter就是自己定义函数,因为用到已有的很少. ...

  3. Django 系列博客(二)

    Django 系列博客(二) 前言 今天博客的内容为使用 Django 完成第一个 Django 页面,并进行一些简单页面的搭建和转跳. 命令行搭建 Django 项目 创建纯净虚拟环境 在上一篇博客 ...

  4. django之创建第7-5-第二种传值方式(time/1232/xiaodneg)

    1.修改views文件 def foo(request,myID,myName): t = loader.get_template("foo.html") user = {&quo ...

  5. Django里面的自定义tag和filter

    Django的文档里面有这么一句 The app that contains the custom tags must be in INSTALLED_APPS  in order for the { ...

  6. Django基础08篇 filter&tag

    1.Django自带的过滤器filter views.py中代码 def template_tags(request): import datetime content = '三胖content三胖c ...

  7. django 自定义过滤器(filter)处理较为复杂的变量的实例

    简述:django 在views中有数据需要通过字典(dict)的方式传递给template,该字典中又包含了字典,而且字典中的键值还是一个对象,在template中处理传递过来的数据的时候,字典不能 ...

  8. [django]添加自定义template filter标签

    看文档templatetag 直接放在app下的templatetag 文件夹下就好,这里想放到一个公共的目录下,然后写下简单的自定义tag的模板. django1.6 创建 在项目目录下建立如下的文 ...

  9. Django的学习进阶(二)———— name

    一.问题: 在做完第一个demo的时候,由于只是基础学习,所以对于name的使用并不需要很熟练,也不用理解的很深.但是在做音乐网站的时候遇到了关于如何使用name的内容. 由于一个app中会使用到另一 ...

  10. django -- 自定义simpletag 和 filter

    django中自定义simpletag,即使用自己定义的函数在html中处理数据. 步骤: 1.创建并注册app settings.py INSTALLED_APPS = [ 'django.cont ...

随机推荐

  1. 【攻防世界】ezbypass-cat

    ezbypass-cat 题目来源 攻防世界 NO.GFSJ1183 题目描述 只有一个登录界面,没有注册界面,扫目录也扫不出有用的文件.sql注入也无果,有些难以下手. 题解一 该题解可能是一个非预 ...

  2. 数据挖掘 | 数据隐私(1) | 差分隐私 | 挑战数据隐私(Some Attempts at Data Privacy)

    L1-Some Attempts at Data Privacy 本随笔基于Gautam Kamath教授的系列课程:CS 860 - Algorithms for Private Data Anal ...

  3. Python基础笔记-Python基础知识(环境、Python解释器、环境变量、基础语法、数据类型等)

    前言 !!!注意:本系列所写的文章全部是学习笔记,来自于观看视频的笔记记录,防止丢失.观看的视频笔记来自于:哔哩哔哩武沛齐老师的视频:2022 Python的web开发(完整版) 入门全套教程,零基础 ...

  4. RCE_STUDY

    概念 RCE(Remote code execution)远程代码执行漏洞,RCE又分命令执行和代码执行. RCE-远程代码执行:远程执行PHP代码 RCE-远程命令执行:远程执行Linux或者Win ...

  5. uniapp支付宝小程序生成分享图方案(最新)

    最近公司业务开发支付宝小程序,功能涉及生成分享图的功能,开始研究实现方案. 开发过微信小程序的小伙伴应该都知道,在微信中生成分享图最常用的方案是使用第三方库Painter GitHub官方仓库地址为: ...

  6. Golang 入门 : 类型系统介绍

    Go语言类型系统 从计算机底层看,所有的数据都是由比特组成,但计算机一般操作的是固定大小的数,如整数.浮点数.比特数组.内存地址等.但是直接操控底层计算机指令进行编程是非常繁琐和容易出错的,所以Go语 ...

  7. deepseek内网离线部署手册

    前言 在当下 AI 浪潮汹涌的时代,DeepSeek 以其卓越的性能和出色的表现,迅速成为了众多专业人士和科技爱好者热议的焦点工具.在众多AI大模型的比拼中,DeepSeek 展现出了优越的实力.然而 ...

  8. 多态的转型和案例--java进阶day02

    1.多态的转型 1.向上转型 我们之前学的多态创建对象,使用的都是向上转型,父类引用指向子类(赋值方式则是从子到父),f拿到子类的地址,就能访问子类的堆内存 2.向下转型 和向上转型相反,子类引用指向 ...

  9. IE 条件注释

    参考文档 IE6 IE7 IE8 IE9 IE10 Css hack及IE条件注释法 IE的有条件注释判定IE版本详解(附实例代码)

  10. 使用Python解决三体问题

    引言 在物理学中,三体问题是一个经典的动态系统问题,它描述了三个天体之间的相互引力作用和运动规律.三体问题最著名的挑战在于它无法通过简单的解析公式来解决,换句话说,三体问题是一个不可解析的问题.尽管如 ...