我发现一个link在Django模板中有一个“switch”标签,但我想知道如果没有它,这是否可以实现。只使用Django自带的东西?基本上,还有其他方法可以使用多个“if”或“ifequal”语句吗?
fdbelqdn1#
从Django 1.4开始,有{% elif %}:
{% elif %}
{% if a %} thing{% elif b %} other thing{% elif c %} another thing{% endif %}
{% if a %}
thing
{% elif b %}
other thing
{% elif c %}
another thing
{% endif %}
yyyllmsg2#
不幸的是,这在默认的Django模板引擎中是不可能的。您必须编写类似这样的丑陋代码来模拟开关。
{% if a %} {{ a }}{% else %} {% if b %} {{ b }} {% else %} {% if c %} {{ c }} {% else %} {{ default }} {% endif %} {% endif %}{% endif %}
{{ a }}
{% else %}
{% if b %}
{{ b }}
{% if c %}
{{ c }}
{{ default }}
或者如果只有一个if条件为真,并且不需要默认值。
{% if a %}{{ a }}{% endif %}{% if b %}{{ b }}{% endif %}{% if c %}{{ c }}{% endif %}
通常,当模板引擎不足以完成你想要的任务时,这是一个信号,表明代码应该被移到Django视图中,而不是模板中。举例来说:
# Django viewif a: val = aelif b: val = belif c: val = celse: val = default# Template{{ val }}
# Django view
if a:
val = a
elif b:
val = b
elif c:
val = c
else:
val = default
# Template
{{ val }}
up9lanfz3#
对于以前的回应者:在不理解用例的情况下,你就做出了假设并批评了提问者。@Ber说“到处都是”,这当然不是提问者所暗示的。不公平我有一个例子,我想在Django模板中的一个地方执行{% switch %}语句。将switch语句的等价物移到Python代码中不仅不方便,而且实际上会使视图和模板更难阅读,并将属于一个地方的简单条件逻辑分成两个地方。在许多情况下,我可以想象{% switch %}(或{% if %})是有用的,不使用一个需要在视图中放置HTML。这是一个更糟糕的罪过,这就是为什么{% if %}首先存在。{% switch %}没有什么不同。幸运的是,Django是可扩展的,很多人已经实现了switch。退房时间:Switch template tag
{% switch %}
% if %}
{% if %}
from django import templatefrom django.template import Library, Node, VariableDoesNotExistregister = Library()@register.tag(name="switch")def do_switch(parser, token): """ The ``{% switch %}`` tag compares a variable against one or more values in ``{% case %}`` tags, and outputs the contents of the matching block. An optional ``{% else %}`` tag sets off the default output if no matches could be found:: {% switch result_count %} {% case 0 %} There are no search results. {% case 1 %} There is one search result. {% else %} Jackpot! Your search found {{ result_count }} results. {% endswitch %} Each ``{% case %}`` tag can take multiple values to compare the variable against:: {% switch username %} {% case "Jim" "Bob" "Joe" %} Me old mate {{ username }}! How ya doin? {% else %} Hello {{ username }} {% endswitch %} """ bits = token.contents.split() tag_name = bits[0] if len(bits) != 2: raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name) variable = parser.compile_filter(bits[1]) class BlockTagList(object): # This is a bit of a hack, as it embeds knowledge of the behaviour # of Parser.parse() relating to the "parse_until" argument. def __init__(self, *names): self.names = set(names) def __contains__(self, token_contents): name = token_contents.split()[0] return name in self.names # Skip over everything before the first {% case %} tag parser.parse(BlockTagList('case', 'endswitch')) cases = [] token = parser.next_token() got_case = False got_else = False while token.contents != 'endswitch': nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch')) if got_else: raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name) contents = token.contents.split() token_name, token_args = contents[0], contents[1:] if token_name == 'case': tests = map(parser.compile_filter, token_args) case = (tests, nodelist) got_case = True else: # The {% else %} tag case = (None, nodelist) got_else = True cases.append(case) token = parser.next_token() if not got_case: raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name) return SwitchNode(variable, cases)class SwitchNode(Node): def __init__(self, variable, cases): self.variable = variable self.cases = cases def __repr__(self): return "<Switch node>" def __iter__(self): for tests, nodelist in self.cases: for node in nodelist: yield node def get_nodes_by_type(self, nodetype): nodes = [] if isinstance(self, nodetype): nodes.append(self) for tests, nodelist in self.cases: nodes.extend(nodelist.get_nodes_by_type(nodetype)) return nodes def render(self, context): try: value_missing = False value = self.variable.resolve(context, True) except VariableDoesNotExist: no_value = True value_missing = None for tests, nodelist in self.cases: if tests is None: return nodelist.render(context) elif not value_missing: for test in tests: test_value = test.resolve(context, True) if value == test_value: return nodelist.render(context) else: return ""
from django import template
from django.template import Library, Node, VariableDoesNotExist
register = Library()
@register.tag(name="switch")
def do_switch(parser, token):
"""
The ``{% switch %}`` tag compares a variable against one or more values in
``{% case %}`` tags, and outputs the contents of the matching block. An
optional ``{% else %}`` tag sets off the default output if no matches
could be found::
{% switch result_count %}
{% case 0 %}
There are no search results.
{% case 1 %}
There is one search result.
Jackpot! Your search found {{ result_count }} results.
{% endswitch %}
Each ``{% case %}`` tag can take multiple values to compare the variable
against::
{% switch username %}
{% case "Jim" "Bob" "Joe" %}
Me old mate {{ username }}! How ya doin?
Hello {{ username }}
bits = token.contents.split()
tag_name = bits[0]
if len(bits) != 2:
raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name)
variable = parser.compile_filter(bits[1])
class BlockTagList(object):
# This is a bit of a hack, as it embeds knowledge of the behaviour
# of Parser.parse() relating to the "parse_until" argument.
def __init__(self, *names):
self.names = set(names)
def __contains__(self, token_contents):
name = token_contents.split()[0]
return name in self.names
# Skip over everything before the first {% case %} tag
parser.parse(BlockTagList('case', 'endswitch'))
cases = []
token = parser.next_token()
got_case = False
got_else = False
while token.contents != 'endswitch':
nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch'))
if got_else:
raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name)
contents = token.contents.split()
token_name, token_args = contents[0], contents[1:]
if token_name == 'case':
tests = map(parser.compile_filter, token_args)
case = (tests, nodelist)
got_case = True
# The {% else %} tag
case = (None, nodelist)
got_else = True
cases.append(case)
if not got_case:
raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name)
return SwitchNode(variable, cases)
class SwitchNode(Node):
def __init__(self, variable, cases):
self.variable = variable
self.cases = cases
def __repr__(self):
return "<Switch node>"
def __iter__(self):
for tests, nodelist in self.cases:
for node in nodelist:
yield node
def get_nodes_by_type(self, nodetype):
nodes = []
if isinstance(self, nodetype):
nodes.append(self)
nodes.extend(nodelist.get_nodes_by_type(nodetype))
return nodes
def render(self, context):
try:
value_missing = False
value = self.variable.resolve(context, True)
except VariableDoesNotExist:
no_value = True
value_missing = None
if tests is None:
return nodelist.render(context)
elif not value_missing:
for test in tests:
test_value = test.resolve(context, True)
if value == test_value:
return ""
htzpubme4#
在一个非常普遍的观点中,对switch语句的需要是一个信号,表明需要创建新的类和对象来捕获不同的“情况”。然后,你只需要调用一个对象方法或引用一个对象属性,而不是到处“切换“。
n1bvdmb65#
这是Roy写的代码的固定版本:
@register.tag(name="case")def case_tag(parser, token): pass@register.tag(name="switch")def switch_tag(parser, token): """ The ``{% switch %}`` tag compares a variable against one or more values in ``{% case %}`` tags, and outputs the contents of the matching block. An optional ``{% else %}`` tag sets off the default output if no matches could be found:: {% switch result_count %} {% case 0 %} There are no search results. {% case 1 %} There is one search result. {% else %} Jackpot! Your search found {{ result_count }} results. {% endswitch %} Each ``{% case %}`` tag can take multiple values to compare the variable against:: {% switch username %} {% case "Jim" "Bob" "Joe" %} Me old mate {{ username }}! How ya doin? {% else %} Hello {{ username }} {% endswitch %} """ bits = token.contents.split() tag_name = bits[0] if len(bits) != 2: raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name) variable = parser.compile_filter(bits[1]) class BlockTagList(object): # This is a bit of a hack, as it embeds knowledge of the behaviour # of Parser.parse() relating to the "parse_until" argument. def __init__(self, *names): self.names = set(names) def __contains__(self, token_contents): name = token_contents.split()[0] return name in self.names # Skip over everything before the first {% case %} tag # TODO: error if there is anything here! parser.parse(BlockTagList('case', 'endswitch')) cases = [] token = parser.next_token() got_case = False got_else = False while token.contents != 'endswitch': nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch')) if got_else: raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name) contents = token.split_contents() token_name, token_args = contents[0], contents[1:] if token_name == 'case': tests = map(parser.compile_filter, token_args) case = (tests, nodelist) got_case = True else: # The {% else %} tag assert token_name == 'else' case = (None, nodelist) got_else = True cases.append(case) token = parser.next_token() if not got_case: raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name) return SwitchNode(variable, cases)class SwitchNode(Node): def __init__(self, variable, cases): self.variable = variable self.cases = cases def __repr__(self): return "<Switch node>" def __iter__(self): for tests, nodelist in self.cases: for node in nodelist: yield node def get_nodes_by_type(self, nodetype): nodes = [] if isinstance(self, nodetype): nodes.append(self) for tests, nodelist in self.cases: nodes.extend(nodelist.get_nodes_by_type(nodetype)) return nodes def render(self, context): value_missing = False value = self.variable.resolve(context, True) for tests, nodelist in self.cases: if tests is None: return nodelist.render(context) elif not value_missing: for test in tests: test_value = test.resolve(context, True) if value == test_value: return nodelist.render(context) assert False, f'No case hit for value {value}'
@register.tag(name="case")
def case_tag(parser, token):
pass
def switch_tag(parser, token):
# TODO: error if there is anything here!
contents = token.split_contents()
assert token_name == 'else'
assert False, f'No case hit for value {value}'
测试验证:
import pytestfrom django.template import ( Context, Template,)def test_switch(): assert Template(''' {% load base %} {% switch foo %} {% case 1 %} foo {% endswitch %} ''').render(Context(dict(foo=1))).strip() == 'foo' assert Template(''' {% load base %} {% switch foo %} {% case 1 %} foo {% else %} bar {% endswitch %} ''').render(Context(dict(foo=2))).strip() == 'bar' assert Template(''' {% load base %} {% switch foo %} {% case 1 %} foo {% case 2 %} bar {% endswitch %} ''').render(Context(dict(foo=2))).strip() == 'bar' assert Template(''' {% load base %} {% switch foo %} {% case "hello world" %} foo {% case "good bye world" %} bar {% endswitch %} ''').render(Context(dict(foo="hello world"))).strip() == 'foo' with pytest.raises(AssertionError): Template(''' {% load base %} {% switch foo %} {% case 1 %} foo {% endswitch %} ''').render(Context(dict(foo=0))) with pytest.raises(AssertionError): Template(''' {% load base %} {% switch foo %} {% case "hello world" %} foo {% case "good bye world" %} bar {% endswitch %} ''').render(Context(dict(foo="something else"))).strip()
import pytest
from django.template import (
Context,
Template,
)
def test_switch():
assert Template('''
{% load base %}
{% switch foo %}
foo
''').render(Context(dict(foo=1))).strip() == 'foo'
bar
''').render(Context(dict(foo=2))).strip() == 'bar'
{% case 2 %}
{% case "hello world" %}
{% case "good bye world" %}
''').render(Context(dict(foo="hello world"))).strip() == 'foo'
with pytest.raises(AssertionError):
Template('''
''').render(Context(dict(foo=0)))
''').render(Context(dict(foo="something else"))).strip()
5条答案
按热度按时间fdbelqdn1#
从Django 1.4开始,有
{% elif %}
:yyyllmsg2#
不幸的是,这在默认的Django模板引擎中是不可能的。您必须编写类似这样的丑陋代码来模拟开关。
或者如果只有一个if条件为真,并且不需要默认值。
通常,当模板引擎不足以完成你想要的任务时,这是一个信号,表明代码应该被移到Django视图中,而不是模板中。举例来说:
up9lanfz3#
对于以前的回应者:在不理解用例的情况下,你就做出了假设并批评了提问者。@Ber说“到处都是”,这当然不是提问者所暗示的。不公平
我有一个例子,我想在Django模板中的一个地方执行
{% switch %}
语句。将switch语句的等价物移到Python代码中不仅不方便,而且实际上会使视图和模板更难阅读,并将属于一个地方的简单条件逻辑分成两个地方。在许多情况下,我可以想象
{% switch %}
(或{% if %}
)是有用的,不使用一个需要在视图中放置HTML。这是一个更糟糕的罪过,这就是为什么{% if %}
首先存在。{% switch %}
没有什么不同。幸运的是,Django是可扩展的,很多人已经实现了switch。退房时间:
Switch template tag
htzpubme4#
在一个非常普遍的观点中,对switch语句的需要是一个信号,表明需要创建新的类和对象来捕获不同的“情况”。
然后,你只需要调用一个对象方法或引用一个对象属性,而不是到处“切换“。
n1bvdmb65#
这是Roy写的代码的固定版本:
测试验证: