Django 标签过滤器

django内置标签

autoescape

控制当前的自动转义行为。这个标记可以作为参数打开或关闭,它决定自动转义是否在块内有效。块使用endautoescape结束标记关闭。
当自动转义生效时,所有变量内容在将结果放入输出之前(但是在应用了任何过滤器之后)都要对其应用HTML转义。这相当于手动将转义过滤器应用到每个变量。
唯一的例外是那些已经被标记为“安全”的变量,它们不会被转义,或者被填充变量的代码转义,或者因为它已经应用了安全或转义过滤器。

转义,显示普通字符串,不会解析成html标签

{% autoescape on %}
{{ body }}

不转以,解析成html标签

{% autoescape off %}
{{ body }}

block

定义了一个子模块可以继承的块

comment

忽略comment之间的内容,在注释用于记录为什么禁用代码的代码时,这很有用。

csrf_token

此标记用于CSRF保护,防止跨站点伪造请求。

cycle

每次遇到此标记时都会生成它的一个参数。第一个论证产生于第一次相遇,第二个论证产生于第二次相遇,以此类推。一旦所有参数都用完了,标记就会循环到第一个参数,并再次生成它。

The first iteration produces HTML that refers to class row1, the second to row2, the third to row1 again, and so on for each iteration of the loop.

{% for o in some_list %}

...

cycle可以使用模板变量

{% for o in some_list %}

...

循环中包含的变量将被转义。你可以禁用自动转义

{% for o in some_list %}

...

也可以混合使用

{% for o in some_list %}

...

将cycle当做变量使用


...
...


...
...

如果只想声明循环,而不生成第一个值,则可以添加一个silent关键字作为标记中的最后一个关键字。
{% for obj in some_list %}
{% cycle 'row1' 'row2' as rowcolors silent %}
{% include "subtemplate.html" %}

debug

输出整个调试信息负载,包括当前上下文和导入的模块。

extends

引用母版

the app directory

dir1/
template.html
base2.html
my/
base3.html
base1.html

In template.html, the following paths would be valid:

{% extends "./base2.html" %}
{% extends "../base1.html" %}

filter

通过一个或多个过滤器对块的内容进行编辑。可以用管道指定多个过滤器,过滤器可以有参数,就像在变量语法中一样。
注意,该块包含过滤器和endfilter标记之间的所有文本。

变小写

{% filter force_escape|lower %}
This text will be HTML-escaped, and will appear in all lowercase.

firstof

输出第一个不为False的参数变量。如果所有传递的变量都为假,则不输出任何结果。

{% firstof var1 var2 var3 %}

如果传递的值都为False,还可以给一个默认显示

{% firstof var1 var2 var3 "fallback value" %}

转义

{% autoescape off %}
{% firstof var1 var2 var3 "fallback value" %}

如果只需要单独转义

{% firstof var1 var2|safe var3 "fallback value"|safe %}

for

列表循环


    {% for athlete in athlete_list %}
  • {{ athlete.name }}

  • {% endfor %}

字典循环

{% for key, value in data.items %}
{{ key }}: {{ value }}

forloop

forloop.counter 从1开始记录循环索引
forloop.counter0 从0开始记录循环索引
forloop.revcounter 反转显示forloop.counter
forloop.revcounter0 反转显示forloop.counter0
forloop.first 是否为循环的第一次 返回True/False
forloop.last 是否为训话你的最后一次 返回True/False
forloop.parentloop 对于循环嵌套,表示当前循环的父循环

for … empty

for标记可以采用一个可选的{% empty %}子句,如果给定的数组为空或找不到,则会显示其文本:

if

条件语句

{% if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
Athletes should be out of the locker room soon!
{% else %}
No athletes.

ifequal and ifnotequal

一种过时的{% id a==b %}的写法

ischanged

检查一个变量自上次循环之后是否发生了改变

Archive for {{ year }}

{% for date in days %}
{% ifchanged %}

{{ date|date:"F" }}

{% endifchanged %}
<a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}

include

在模板中嵌套模板

嵌套的模板和当前模板使用同一个上下文

{% include "demo.html" %}

load

加载自定义模板标记集。

{% load somelibrary %}

lorem

显示随机的“lorem ipsum”拉丁文本。这对于在模板中提供示例数据非常有用

count:个数
methnod:w表示单词,p表示HTML段落,b表示纯文本段落(默认为b)
random

regroup

通过一个公共属性重新组合一组相似的对象

grouper – the item that was grouped by (e.g., the string “India” or “Japan”).

list – a list of all items in this group (e.g., a list of all cities with country=’India’).

模板变量

cities = [
{'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
{'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
{'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
{'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
{'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
]

调用regroup方法

{% regroup cities by country as country_list %}


    {% for country in country_list %}
  • {{ country.grouper }

      {% for city in country.list %}
    • {{ city.name }}: {{ city.population }}

    • {% endfor %}


  • {% endfor %}

display

India
Mumbai: 19,000,000
Calcutta: 15,000,000
USA
New York: 20,000,000
Chicago: 7,000,000
Japan
Tokyo: 33,000,000

调用方法二

{% regroup cities by country as country_list %}


    {% for country, local_cities in country_list %}
  • {{ country }}

      {% for city in local_cities %}
    • {{ city.name }}: {{ city.population }}

    • {% endfor %}


  • {% endfor %}

注:regroup不会对输入进行排序,如果输入的列表不是按需求字段排序好的,nameregroup将会把它们显示为不同的列。

这个问题最简单的解决方案是在视图代码中确保数据按照您想要显示的方式排序。
另一个解决方案是使用dictsort过滤器对模板中的数据进行排序,如果您的数据位于字典列表中

{% regroup cities|dictsort:"country" by country as country_list %}

任何有效的模板查找都是重新组标记的合法分组属性,包括方法、属性、字典键和列表项。例如,如果“country”字段是具有“description”属性的类的外键,则可以使用

{% regroup cities by country.description as country_list %}

或者,如果country是一个有选项的字段,它将有get_FOO_display()方法作为属性可用,允许您对显示字符串进行分组,而不是选择键:

resetcycle

重新设置前一个循环,以便在下次遇到第一个项目时重新开始。如果没有参数,{% resetcycle %}将重置模板中定义的最后一个{% cycle %}。

spaceless

删除HTML标记之间的空白。这包括制表符和换行符。不会删除文本间的空格。

templatetag

显示特殊字符

Argument Outputs
openblock {%
closeblock %}
openvariable {{
closevariable }}
openbrace {
closebrace }
opencomment {#
closecomment #}

{% templatetag openblock %} url 'entry_list' {% templatetag closeblock %}

url

加载namespace中的路由

<a href="{% url "login" %}">登录

带参数

{% url 'some-url-name' arg1=v1 arg2=v2 %}

不直接显示,保存在变量里

{% url 'some-url-name' arg arg2 as the_url %}

I'm linking to {{ the_url }}

检索带有名称空间的URL,请指定完全限定名

{% url 'myapp:view-name' %}

verbatim

停止模板引擎呈现此块标记的内容。
一个常见的用法是允许JavaScript模板层与Django的语法发生冲突

{% verbatim %}
{{if dying}}Still alive.{{/if}}

{% verbatim myblock %}
Avoid template rendering via the {% verbatim %}{% endverbatim %} block.

with

以更简单的名称缓存复杂的变量。当访问多次“昂贵”的方法(例如,访问数据库的方法)时,这非常有用

{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}

可以同时命名多个变量
{% with alpha=1 beta=2 %}
...

过滤器

add

加参数值给value

{{ value|add:"2" }}

此筛选器将首先尝试将两个值强制转换为整数。如果失败,它将尝试将这些值相加。这将在某些数据类型(字符串、列表等)上工作,在其他类型上失败。如果失败,结果将是一个空字符串

{{ first|add:second }}

first is [1, 2, 3] and second is [4, 5, 6], then the output will be [1, 2, 3, 4, 5, 6].

addslashes

在引号前加斜杠。例如,用于在CSV中转义字符串。

If value is "I'm using Django", the output will be "I'm using Django".

capfirst

将值的首字母大写,如果不是字母,该过滤无效

center

将值集中在给定宽度的字段中。

{{ value|center:"15" }}

cut

从给定字符串中删除所有arg值。

{{ value|cut:" " }}

date
根据给定的格式格式化日期。

{{ value|date:"D d M Y" }}

传递的格式可以是预定义的格式之一DATE_FORMAT、DATETIME_FORMAT、SHORT_DATE_FORMAT或SHORT_DATETIME_FORMAT,或使用上面表中显示的格式说明符的自定义格式。请注意,预定义格式可能因当前语言环境而异。

{{ value|date:"SHORT_DATE_FORMAT" }}

default

如果value为False,则显示denfalut过滤器的参数值

{{ value|default:"nothing" }}

default_if_none

如果value值为None,则显示defalut过滤器的参数值

{{ value|default_if_none:"nothing" }}

dictsort

获取字典列表并返回按参数中给定的键排序的列表。

value = [
{'name': 'zed', 'age': 19},
{'name': 'amy', 'age': 22},
{'name': 'joe', 'age': 31},
]

{{ value|dictsort:"name" }}

output:

[
{'name': 'amy', 'age': 22},
{'name': 'joe', 'age': 31},
{'name': 'zed', 'age': 19},
]

高级用法:

value = [
{'title': '1984', 'author': {'name': 'George', 'age': 45}},
{'title': 'Timequake', 'author': {'name': 'Kurt', 'age': 75}},
{'title': 'Alice', 'author': {'name': 'Lewis', 'age': 33}},
]

{% for book in books|dictsort:"author.age" %}
* {{ book.title }} ({{ book.author.name }})

output

* Alice (Lewis)
* 1984 (George)
* Timequake (Kurt)

value=[
('a', '42'),
('c', 'string'),
('b', 'foo'),
]

{{ value|dictsort:0 }} # 0不能写成"0"

output

[
('a', '42'),
('b', 'foo'),
('c', 'string'),
]

dictsortreversed

与dictsort排序相反

divisibleby

如果值可被参数整除,则返回True。

{{ value|divisibleby:"3" }}

value=21,return True;value=22,return False

escape

转义字符串的HTML。具体来说,它使这些替换:

{% autoescape off %}
{{ title|escape }}

escapejs

转义用于JavaScript字符串的字符。这并不能保证字符串在HTML或JavaScript模板文本中使用时是安全的,但是可以在使用模板生成JavaScript/JSON时防止语法错误。

{{ value|escapejs }}

filesizeformat

把数字转换成字节大小

{{ value|filesizeformat }}

value=123456789,return 117.7 MB

first

返回列表中的第一个值

{{ value|first }}

value=[1,2,3,4,5],return 1

floatformat

在不使用参数的情况下,将浮点数四舍五入到小数点后一位——但前提是要显示小数部分。

value Template Output
34.23234 {{ value|floatformat }} 34.2
34.00000 {{ value|floatformat }} 34
34.26000 {{ value|floatformat }} 34.3

value Template Output
34.23234 {{ value|floatformat:3 }} 34.232
34.00000 {{ value|floatformat:3 }} 34.000
34.26000 {{ value|floatformat:3 }}

value Template Output
34.23234 {{ value|floatformat:"0" }} 34
34.00000 {{ value|floatformat:"0" }} 34
39.56000 {{ value|floatformat:"0" }} 40

value Template Output
34.23234 {{ value|floatformat:"-3" }} 34.232
34.00000 {{ value|floatformat:"-3" }} 34
34.26000 {{ value|floatformat:"-3" }} 34.260

force_escape

get_digit

返回数字的后数第几位的值

{{ "123456789"|get_digit:4 }} #6
{{ 123456789|get_digit:"2" }} #8

iriencode

将IRI(国际化资源标识符)转换为适合包含在URL中的字符串。如果您试图使用URL中包含非ascii字符的字符串,那么这是必要的。
在已经通过urlencode筛选器的字符串上使用此筛选器是安全的。

{{ value|iriencode }}

join

使用字符串连接列表,比如Python的string .join(list)

{{ value|join:" // " }}

value=['a','b','c'],return "a // b // c"

json_script

安全地将Python对象输出为JSON,包装在<script>标记中,以便与JavaScript一起使用。
参数:<script>标签的HTML " id "。

{{ value|json_script:"hello-data" }}

output

相当于javascript代码

var value = JSON.parse(document.getElementById('hello-data').textContent);

last

返回列表中的最后一项

{{ value|last }}

length

返回列表的长度

{{ value|length }}

length_is

返回长度是否等于参数

{{ value|length_is:"4" }}

linebreaks

用适当的HTML替换纯文本中的换行符;一个换行符变成了HTML换行符(
),一个新行加上一个空行变成了段落换行符(

)。

{{ value|linebreaks }}

If value is Joel\nis a slug, the output will be

Joel
is a slug

.

linebreaksbr

将纯文本中的所有换行符转换为HTML换行符(
)。

{{ value|linebreaksbr }}

linenumbers

显示带有行号的文本。

{{ value|linenumbers }}

lower

将字符串转换为所有小写字母。

{{ value|lower }}

make_list

将value转换成list

{{ value|make_list }}

value="joel",return ['J','o','e','l']

phone2numeric

将电话号码(可能包含字母)转换为它的数值等效项。
输入不一定是有效的电话号码。这将愉快地转换任何字符串。

{{ value|phone2numeric }}

value=800-COLLECT,return 800-2655328

pluralize

如果值不是1则显示一个后缀,默认后缀为s

默认后缀s

You have {{ num_messages }} message{{ num_messages|pluralize }}.

自定义后缀

You have {{ num_walruses }} walrus{{ num_walruses|pluralize:"es" }}.

两个参数 第一个表示1显示的后缀 第二个表示非1显示的后缀

You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}

random

返回列表中的任意值

{{ value|random }}

ljust

左对齐给定宽度字段中的值

{{ value|ljust:"10" }}

rjust

右对齐给定宽度字段中的值

{{ value|ljust:"10" }}

safe

将字符串标记为在输出之前不需要进一步的HTML转义。当自动转义关闭时,此筛选器无效。

{{ var|safe }}

如果您正在链接过滤器,在safe之后应用的过滤器会使内容再次不安全。

safeseq

将安全过滤器应用于序列的每个元素。与其他对序列(如连接)进行操作的过滤器一起使用。

{ some_list|safeseq|join:", " }}

slice

返回列表分割的一部分。

{{ some_list|slice:":2" }}

some_list=['a','b','c'],return ['a','b']

stringformat

根据参数(字符串格式说明符)格式化变量。

{{ value|stringformat:"E" }}

striptags

清楚value中的html标签

{{ value|striptags }}

time

格式化时间

{{ value|time:"H:i" }}

return "01:23"

timesince

将日期格式化为日期之后的时间(例如,“4天,6小时”)。

{{ blog_date|timesince:comment_date }}

return 两个时间的时间差

timeuntil

与timesince类似,格式显示(“4周”)

{{ conference_date|timeuntil:from_date }}

title

将value按title形式显示

{{ value|title }}

truncatechars

将value截断加...显示

{{ value|truncatechars:9 }}

truncatechars_html

与truncatechars类似,可接受html字符串,并忽略html标签 只截断文本内容

{{ value|truncatechars_html:9 }}

truncatewords

与truncatechars类似,截断多少个word。

{{ value|truncatewords:2 }}

If value is "Joel is a slug", the output will be "Joel is ...".

truncatewords_html

与truncatewords类似,可接受htnm字符串

unordered_list

递归地获取一个自嵌套列表并返回一个HTML无序列表——不需要打开和关闭

    标签。

    upper

    将value值变大写

    {{ value|upper }}

    urlencode

    转义url字符串

    {{ value|urlencode }}

    urlize

    将文本中的url或者email地址转换成可以点击的<a>标签

    {{ value|urlize }}

    urlizetrunc

    与urlize类似,可以截断url字符

    {{ value|urlizetrunc:15 }}

    value="Check out www.djangoproject.com",return 'Check out www.djangopr...'

    wordcount

    返回单词个数

    {{ value|wordcount }}

    value="Joel is a slug",return 4

    wordwrap

    将单词包装在指定的行长度

    {{ value|wordwrap:5 }}

    static

    加载STATIC_ROO到当前template

    {% load static %}

    <img src="{% static "images/hi.jpg" %}" alt="Hi!">

    get_static_prefix

    如果您需要对static_url被注入到模板的确切位置和方式有更多的控制,您可以使用get_static_prefix模板标记

    {% load static %}
    Hi!

    {% load static %}

    Hi!
    Hello!

    get_media_prefix

    与get_static_prefix类似,get_media_prefix使用媒体前缀MEDIA_URL填充一个模板变量

    {% load static %}

    django自定义标签和过滤器

        django模板提供了丰富的标签和过滤器用来满足应用程序逻辑表示需求。但是有时,这些内置的功能不能满足需求,就可以通过自定义标记和过滤器来扩展模板引擎,然后再使用{% load %}标记将它们提供给你的模板。

        自定义标记和过滤器一般在app内部指定,或者添加在一个新的app中。它们应该存在一个名叫templatetags的包中。

        自定义标记和过滤器的名字与模板load的名字相同,应避免与其他app中的自定义标记和过滤器名字相同。

    the app layout

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

    in your template you would use the following

    {% load poll_extras %}

        包含自定义标记和过滤器的app必须在setting文件的INSTALLED_APPS中,

        要成为有效的标记库,模块必须包含一个名为register的模块级变量,该变量是一个模板。库实例,其中注册了所有标记和过滤器。

    from django import template

    register = template.Library()

    写一个过滤器

        自定义过滤器只是一个ptyhon function,它可以有一个或者两个参数。
    1. 变量的值不一定是一个字符串
    • 变量可以有一个默认值,或者完全忽略
        注册一个过滤器
    • 您需要通过一个django.template.Library实例来注册过滤器

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

    • 也可以使用装饰器

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

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

    注:如果register.filter不声明name参数,django将使用函数名当作过滤器名称

    例子:

    poll_extras.py定义过滤器

    @register.filter
    def first_filter(intval1, intval2=1):
    return intval1 / intval2

    app_test.html使用过滤器

    {% load poll_extras %}
    {{ 4 | first_filter:2 }} # 2.0
    {{ 4 | first_filter }} # 4.0

    注:大多数过滤器不接受参数。在这种情况下,只需将参数排除在函数之外。例子:

    def lower(value): # Only one argument.
    """Converts a string into all lowercase"""
    return value.lower()

    如果您定义的过滤器需要限定第一个参数为string类型,就可以使用stringfilter装饰器。

    from django import template
    from django.template.defaultfilters import stringfilter

    register = template.Library()

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

    template.Library().filter()参数

    1.is_safe

    将filter返回的结果以原样输出,不进行转义,通常包含HTML标签使其在模板上正常显示。

    @register.filter(is_safe=True)
    def third_demo_filter(value):
    return '%s

    哈哈,

    ' % value

    2.mark_safe

    使用mark_safe函数标记后,django将不再对该函数的内容进行转义。

    @register.filter()
    def third_demo_filter(value):
    return mark_safe(value)

    3.needs_autoescape、autoescape

    为了让过滤器知道当前的自动转义状态,在注册过滤器函数时将needs_autoescape标志设置为True。(如果不指定此标志,则默认为False)。此标志告诉Django,您的筛选器函数希望被传递一个额外的关键字参数,称为autoescape,如果自动转义生效,则为真,否则为假。建议将autoescape参数的默认值设置为True,这样如果从Python代码调用该函数,默认情况下就启用了转义。

    @register.filter(needs_autoescape=True)
    def initial_letter_filter(text, autoescape=True):
    print('result2', autoescape)
    first, other = text[0], text[1:]
    if autoescape:
    esc = conditional_escape
    else:
    esc = lambda x: x
    result = '%s%s' % (esc(first), esc(other))
    print('autoescape',autoescape) # True
    return mark_safe(text)

    4.expects_localtime

    当设置此标志时,如果过滤器的第一个参数是时区感知的datetime, Django将根据模板中时区转换的规则将其转换为当前时区。

    @register.filter(expects_localtime=True)
    def businesshours(value):
    try:
    return 9 <= value.hour < 17
    except AttributeError:
    return ''

    写一个标签

    1.Simple tags

    django.template.Library.simple_tag()

    takes_context

    如果模板标记需要访问当前上下文,那么在注册标记时可以使用takes_context参数。

    @register.simple_tag(takes_context=True)
    def current_time(context, format_string): #注意,第一个参数必须称为context
    timezone = context['timezone']
    return your_get_current_time_method(timezone, format_string)

    Simple_tags可以提供多参数

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

    template调用 以空格作为分隔将参数传给标签

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

    注:可以将标记结果存储在模板变量中,而不是直接输出它。这是通过使用变量名后面的as参数来完成的。这样做可以让您自己在您认为合适的地方输出内容

    {% current_time "%Y-%m-%d %I:%M %p" as the_time %}

    The time is {{ the_time }}.

    2.Inclusion tags

    首先,定义接受参数并为结果生成数据字典的函数。这里重要的一点是,我们只需要返回一个字典,而不是任何更复杂的东西。这将用作模板片段的模板上下文

    def show_results(poll):
    choices = poll.choice_set.all()
    return {'choices': choices}
    接下来,创建用于呈现标记输出的模板。此模板是标记的固定特性:标记编写器指定它,而不是模板设计器。按照我们的示例,模板非常简单


      {% for choice in choices %}
    • {{ choice }}

    • {% endfor %}

    现在,通过调用Library对象上的inclusion_tag()方法来创建并注册包含标记。按照我们的示例,如果上面的模板在一个名为results的文件中。html在一个由模板加载器搜索的目录中,我们会这样注册标签:

    Here, register is a django.template.Library instance, as before

    @register.inclusion_tag('results.html')
    def show_results(poll):
    ...

    另外,也可以使用django.template来注册包含标签。模板实例:

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

    takes_context上下文

    @register.inclusion_tag('link.html', takes_context=True)
    def jump_link(context):
    # home_link是views.py传给template的值
    return {
    'link': context['home_link'],
    'title': context['home_title'],
    }

    进阶标签

    from django import template
    import datetime

    register = template.Library()

    def do_current_time(parser, token): # 注册方法
    try:
    # split_contents() knows not to split quoted strings.
    tag_name, format_string = token.split_contents()
    except ValueError:
    raise template.TemplateSyntaxError(
    "%r tag requires a single argument" % token.contents.split()[0]
    )
    if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
    raise template.TemplateSyntaxError(
    "%r tag's argument should be in quotes" % tag_name
    )
    return CurrentTimeNode(format_string[1:-1])

    class CurrentTimeNode(template.Node): # 节点
    def init(self, format_string):
    self.format_string = format_string

    def render(self, context): # 节点实际运行的方法
    return datetime.datetime.now().strftime(self.format_string)

    register.tag('current_time', do_current_time) # 注册

    多线程安全的节点

    class CycleNode(template.Node):
    def init(self, cyclevars):
    self.cyclevars = cyclevars

    def render(self, context):
    if self not in context.render_context:
    context.render_context[self] = itertools.cycle(self.cyclevars)
    cycle_iter = context.render_context[self]
    return next(cycle_iter)

    传递对象属性到标签

    调用

    This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.

    from django import template

    def do_format_time(parser, token):
    try:
    # split_contents() knows not to split quoted strings.
    tag_name, date_to_be_formatted, format_string = token.split_contents()
    except ValueError:
    raise template.TemplateSyntaxError(
    "%r tag requires exactly two arguments" % token.contents.split()[0]
    )
    if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
    raise template.TemplateSyntaxError(
    "%r tag's argument should be in quotes" % tag_name
    )
    return FormatTimeNode(date_to_be_formatted, format_string[1:-1])

    class FormatTimeNode(template.Node):
    def init(self, date_to_be_formatted, format_string):
    self.date_to_be_formatted = template.Variable(date_to_be_formatted)
    self.format_string = format_string

    def render(self, context):
    try:
    actual_date = self.date_to_be_formatted.resolve(context)
    return actual_date.strftime(self.format_string)
    except template.VariableDoesNotExist:
    return ''

    通常,如果您的模板标记设置了模板变量而不是输出值,则会更加灵活。这样,模板作者就可以重用模板标记创建的值。
    要在上下文中设置变量,只需对render()方法中的上下文对象使用字典赋值。下面是CurrentTimeNode的更新版本,它设置了一个模板变量current_time,而不是输出它:

    import datetime
    from django import template

    class CurrentTimeNode2(template.Node):
    def init(self, format_string):
    self.format_string = format_string
    def render(self, context):
    context['current_time'] = datetime.datetime.now().strftime(self.format_string)
    return ''

    调用

    {% current_time "%Y-%M-%d %I:%M %p" %}

    The time is {{ current_time }}.

    注:上下文中的任何变量集都只能在分配它的模板的相同块中可用。这种行为是有意的;它为变量提供了一个作用域,这样它们就不会与其他块中的上下文发生冲突。

    但是,CurrentTimeNode2有一个问题:变量名current_time是硬编码的。这意味着您需要确保您的模板在其他地方不使用{{current_time}},因为{% current_time %}将盲目地覆盖该变量的值。更清晰的解决方案是让模板标记指定输出变量的名称,如下所示:

    调用

    {% current_time "%Y-%M-%d %I:%M %p" as my_current_time %}

    The current time is {{ my_current_time }}.

    import re

    class CurrentTimeNode3(template.Node):
    def init(self, format_string, var_name):
    self.format_string = format_string
    self.var_name = var_name
    def render(self, context):
    context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
    return ''

    def do_current_time(parser, token):
    # This version uses a regular expression to parse tag contents.
    try:
    # Splitting by None == splitting by spaces.
    tag_name, arg = token.contents.split(None, 1)
    except ValueError:
    raise template.TemplateSyntaxError(
    "%r tag requires arguments" % token.contents.split()[0]
    )
    m = re.search(r'(.*?) as (\w+)', arg)
    if not m:
    raise template.TemplateSyntaxError("%r tag had invalid arguments" % tag_name)
    format_string, var_name = m.groups()
    if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
    raise template.TemplateSyntaxError(
    "%r tag's argument should be in quotes" % tag_name
    )
    return CurrentTimeNode3(format_string[1:-1], var_name)

    解析直到另一个块标记

    模板标签可以协同工作。例如,标准的{% comment %}标签会隐藏所有内容,直到{% endcomment %}。要创建这样的模板标记,在编译函数中使用parser.parse()。
    下面是如何实现简化的{% comment %}标签:
    def do_comment(parser, token):
    nodelist = parser.parse(('endcomment',))
    parser.delete_first_token()
    return CommentNode()

    class CommentNode(template.Node):
    def render(self, context):
    return ''

    parse()使用块标记的一个元组名称“解析到”。它返回一个django.template的实例。NodeList,它是解析器在遇到元组中的任何标记之前遇到的所有节点对象的列表。
    在上述示例中的“nodelist = parser.parse(('endcomment',))”中,nodelist是{% comment %}和{% endcomment %}之间的所有节点的列表,不包括{% comment %}和{% endcomment %}本身。
    在调用parser.parse()之后,解析器还没有“使用”{% endcomment %}标记,因此代码需要显式地调用parser.delete_first_token()。
    render()只返回一个空字符串。{% comment %}和{% endcomment %}之间的任何内容都被忽略

    {% comment %}的实际实现略有不同,因为它允许在{% comment %}和{% endcomment %}之间出现损坏的模板标记。它通过调用parser.skip_past('endcomment')而不是parser.parse((('endcomment'),)),后面跟着parser.delete_first_token(),从而避免了节点列表的生成。

posted @ 2018-09-06 22:31  Super-Yan  阅读(583)  评论(0)    收藏  举报