如何向Django自定义模板(块)标签传递参数
我在用Django做可重用的界面组件,尝试用自定义模板标签来实现:
{% panel %}
Some panel content
{% endpanel %}
这个方法可以正常工作,但我没法把面板标题作为参数传进去。我其实想要的是这样的效果:
{% panel 'Panel Title' %}
Some panel content
{% endpanel %}
我在文档里找不到相关的答案。有没有什么方法可以实现这个?如果没有,是否有其他的策略可以使用?
补充说明:请记住,面板内容应该能够接受更多的标记,比如其他标签和块。这就是为什么简单的模板标签对我来说不够用。
详细信息
panel.html
<div class="panel panel-default">
<div class="panel-heading">{{ title|default:"Panel Title" }}</div>
<div class="panel-body">
{{ body }}
</div>
</div>
templatetags/theme.py
from django import template
register = template.Library()
@register.tag
def panel(parser, token):
nodelist = parser.parse(('endpanel',))
parser.delete_first_token()
return PanelNode(nodelist)
class PanelNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
output = self.nodelist.render(context)
t = template.loader.get_template('theme/blocks/panel.html')
c = template.Context({'body': output})
return t.render(c)
2 个回答
0
我也遇到过同样的问题,在看到你的提问后,我终于解决了。希望这能帮助到其他人。
我在我的项目中使用了classy-tags,我非常推荐这个工具。如果你只是打算用一次,代码可以写得很简单。不过因为我想要不同类型的面板,所以我把它做得稍微通用一些。
# templatetags/modals.py
from classytags.core import Tag, Options
from classytags.arguments import Argument, MultiKeywordArgument
from django import template
register = template.Library()
class BasePanel(Tag):
def render_tag(self, context, **kwargs):
nodelist = kwargs.pop('nodelist')
body = nodelist.render(context)
panel_context = self.get_panel_context(kwargs)
panel_context['body'] = body
t = template.loader.get_template(self.template)
c = template.Context(kwargs)
return t.render(c)
def get_panel_context(self, arguments):
"""
Override this method if you're using fancy arguments,
e.g: MultiKeywordArgument
"""
return arguments
class ExamplePanel(BasePanel):
name = 'panel'
template = 'main/modals/panel.html'
options = Options(
Argument('title'),
MultiKeywordArgument('kw', required=False),
blocks=[('endpanel', 'nodelist')],
)
def get_panel_context(self, arguments):
kw = arguments.pop('kw')
arguments['state'] = kw.get('state', 'default')
return arguments
register.tag(ExamplePanel)
这是模板:
# panel.html
<div class="panel panel-{{ state }}">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">
{{ body }}
</div>
</div>
这是使用方法:
{% panel "First Title" state="primary" %}
<p>Hello World!</p>
{% endpanel %}
{% panel "Another Title" %}
<p>Hello World!</p>
{% endpanel %}
这可以很简单地通过Jinja2宏来实现。希望Django 1.8能带来原生的Jinja2支持。
3
我觉得你想要的答案在文档里有写,具体可以查看这个链接:https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#passing-template-variables-to-the-tag
往下翻到简单标签的部分,那里详细说明了如何按照你想要的方式传递变量。
@register.simple_tag
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 %}