Django之自定义模板标签filter,simple_tag,inclusion_tags之间的区别

自定义模板(template)的标签(tags)和过滤器(filters)

  • filter
  • simple_tag
  • inclusion_tag

布局

1.在app中创建templatetags模块

​ 与 models.pyviews.py 等同级。若该目录不存在,创建它——不要忘了用 __init__.py 文件确保目录被视作一个 Python 包。

*添加templatetags模块后,你需要重启服务器,这样才能在模板中使用 tags 和 filters。*

2.创建任意 .py 文件,如:xx.py

小心不要采用一个可能与其它应用自定义的 tags 和 filters 冲突的名字

3.py文件需要注册,在py文件中写入以下代码

from django import template

register = template.Library()

4.html模板需要导入模块

{% load 模块名 %}
#如{% load poll_extras  %},{% load xx  %}

编写自定义的模板过滤器filter

过滤器,如 {{ var|foo:"bar" }}只有两个参数,一个是变量值var,一个是过滤器的参数bar

特点:只能两个参数,不能加空格,能做if条件

​ html:{ 参数1|函数名:参数2}

自定义filter

django.template.Library.filter()

第一种写法

1.定义函数

def cut(value, arg):
    """Removes all values of arg from the given string"""
    return value.replace(arg, '')
def lower(value): # Only one argument.
    """Converts a string into all lowercase"""
    return value.lower()

2.用Library 实例去注册它

register.filter('cut', cut)
register.filter('lower', lower)

#register.filter() 方法有两个参数:

#1.过滤器的名称——字符串。
#2.编辑函数——一个 Python 函数(不是函数名的字符串)。


第二种写法,装饰器

@register.filter(name='cut')
def cut(value, arg):
    return value.replace(arg, '')

@register.filter
def lower(value):
    return value.lower()

#若你不填 name 参数,像第二个例子展示的一样,Django 会将函数名当做过滤器名。

filter()其他参数

register.filter() 也接受 3 个关键字参数, is_safe, needs_autoescape,和 expects_localtime

@register.filter(is_safe=True) 
#安全字符串:是在输出时被标记为安全的字符串,不会进一步转义,即XSS 攻击
#该标志告诉 Django,若一个“安全”字符串传给您的过滤器,结果仍会是安全的。若传入了不安全的字符串,Django 会在需要时自动转义。

@register.filter(needs_autoescape=True)
#自动转义

@register.filter(expects_localtime=True)
#设置该标志后,如果过滤器接收的第一个参数是一个时区敏感的 datetime,Django 在将其传递给过滤器前的某个合适时间将其转换为当前时区的时间

自定义模板标签simple_tag()

特点:可以带多个参数,不能作为if条件

​ html:{% 函数名 arg1 arg2 arg3%}

​ 返回值是字符串形式

simple_tag()定义

@register.simple_tag
def current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

#simple_tag 函数可以接受任意数量的位置或关键字参数
@register.simple_tag
def str_join(*args,**kwargs):
    return '{}_{}'.format('_'.join(args),'*'.join(kwargs.values()))

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

Html模板中

#任意数量的,以空格分隔的参数会被传递给模板标签。与 Python 中类似,关键字参数的赋值使用等号("`=`"),且必须在位置参数后提供。例子:

{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}


#将标签结果存入一个模板变量而不是直接将其输出是可能的。这能通过使用 as 参数,后跟变量名实现。这样做能让你在期望的位置输出内容:

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

simple_tag()其他参数

#模板标签需要访问当前上下文
@register.simple_tag(takes_context=True)
def current_time(context, format_string):
    timezone = context['timezone']
    return your_get_current_time_method(timezone, format_string)

#需要重命名标签,你可以为其提供一个自定义名
register.simple_tag(lambda x: x - 1, name='minusone')

@register.simple_tag(name='minustwo')
def some_function(value):
    return value - 2


包含标签inclusion_tag()

特点:可以带多个参数,

​ 返回值的参数,变量,需要给模板渲染

定义

第一种方式定义

#步骤 
#1定义一个函数,接受参数,并返回一个字典,只需返回一个字典,不是任何其它复杂的东西。这将作为一个模板上下文被模板碎片使用

def show_results(poll):
    choices = poll.choice_set.all()
    return {'choices': choices}

#2创建模板,HTML
<ul>
{% for choice in choices %}
    <li> {{ choice }} </li>
{% endfor %}
</ul>

#3使用标签

{% show_results poll %}

#结果
<ul>
  <li>First choice</li>
  <li>Second choice</li>
  <li>Third choice</li>
</ul>


第二方式

# Here, register is a django.template.Library instance, as before
@register.inclusion_tag('results.html')#results.html模板,在模板加载器搜索的目录中
def show_results(poll):
    ...
     

或者,也能用 [django.template.Template]实例注册包含标签:

from django.template.loader import get_template
t = get_template('results.html')
register.inclusion_tag(t)(show_results)

总之,常用的写法第二种方式,用装饰器

inclusion_tag()参数

#有时候,你的包含标签可能要求超多参数,模板作者不得不传入所有参数,并牢记它们的顺序,非常痛苦。为了解决此问题, Django 为包含标签提供了一个 take_context 选项。如果在创建模板标签时指定了 takes_context,该标签将没有必要的参数,底层 Python 函数将只有一个参数——标签创建时的模板上下文。

#举个例子,假设你编写了一个包含标签,总会在一个包含指向首页的 home_link 和 home_title 的上下文环境下使用。Python 函数看起来会像这样:


@register.inclusion_tag('link.html', takes_context=True)
def jump_link(context):
    return {
        'link': context['home_link'],
        'title': context['home_title'],
    }


#注意,该函数的第一个参数 必须 是 context。

#在 register.inclusion_tag() 行,我们制定了模板名并设置 takes_context=True。以下是模板 link.html 的样子:

Jump directly to <a href="{{ link }}">{{ title }}</a>.


#后面,当你想用该自定义标签时,加载它的库,并不带任何参数的调用它,像这样:

{% jump_link %}


注意,只要使用了 takes_context=True,就无需为模板标签传递参数。它自动从上下文获取。

takes_context 参数默认为 False。当其为 True,标签会被传入上下文对象,像本例展示的那样。这是本例和之前的 包含标签 实例的唯一不同之处。


包含标签 函数能接受任意个数的位置或关键字参数。例子:

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


随后在模板中,任意数量的,以空格分隔的参数会被传递给模板标签。与 Python 中类似,关键字参数的赋值使用等号("="),且必须在位置参数后提供。例子:



{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}

动态页面方便

三者之间的比较

三者共同点:前提布局是一样的

写函数 + 加装饰器

#filter只能两个参数,可以用if判断语句
@register.filter	
def add_arg(value,arg):
	return  'xxxx'


#simple_tag可以多个参数,不可以用if判断语句,返回数据是以字符串形式,比较单一
@register.simple_tag	
def str_join(*args, **kwargs):
    return "{}_{}".format('_'.join(args), '*'.join(kwargs.values()))


#可以多个参数,不可以用if判断语句,数据返回字典形式,可复杂操作
@register.inclusion_tag('page.html')	
def pagination(num):
    return {'num': range(1, num + 1)}

inclusion_tag的模板page.html

<nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        {% for li in num %}
            <li><a href="#">{{ li }}</a></li>
        {% endfor %}

        <li>
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>

模板html使用

#共同点:导入库

{% load 模块名 %}

{% load mytags %}


#不同点
#filter	
{{ somevariable|cut:"0" }} #是以两个大括号括起来的

{{ 'alex'|add_arg:'dsb' }}

#simple_tag
#inclusion_tag
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %} #两者相同,是以大括号内包含百分号包裹


{% str_join 'a' 'b' 'c' k1='d' k2='e' k3='f' %}

{% pagination 10 %}

simple_tag与inclusion_tag之间的对比示例

比如下面做个分页,

首先,两者前提都在app下创建templatetags,在templatetags里创建mytags.py文件

simple_tag写法

from django import template

register = template.Library()
from django.utils.safestring import mark_safe #告诉django此代码是安全性的,不需要转义

@register.simple_tag
def pagination(num):
    li_list  =  [ '<li><a href="#">{}</a></li>'.format(i) for i in range(1,num+1)  ]

    return mark_safe("""
    <nav aria-label="Page navigation">
                    <ul class="pagination">
                        <li>
                            <a href="#" aria-label="Previous">
                                <span aria-hidden="true">&laquo;</span>
                            </a>
                        </li>
                        {}
                        <li>
                            <a href="#" aria-label="Next">
                                <span aria-hidden="true">&raquo;</span>
                            </a>
                        </li>
                    </ul>
                </nav>""".format(''.join(li_list)))

inclusion_tag写法

mytags.py文件

from django import template

register = template.Library()
from django.utils.safestring import mark_safe


@register.inclusion_tag('page.html')
def pagination(num):
    return {'num': range(1, num + 1)}

模板page.html文件

<nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        {% for li in num %}
            <li><a href="#">{{ li }}</a></li>
        {% endfor %}

        <li>
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>

HTML使用

两者的使用方法相同

{% load mytags %} 	#导入
{% pagination 3 %}	#函数名 +参数
posted @ 2020-06-10 11:32  JIMfan  阅读(238)  评论(0)    收藏  举报