处理自定义Django模板标记中的条件块

时间:2016-02-26 15:40:38

标签: python django

我有一个自定义Django模板标记,它充当条件块:

{% if_has_permission request "some_permission" %}
<div>
    <input type="text" name="sample_1">
    <label><input type="checkbox" name="enable_it"> Enable</label>
</div>
{% endif_has_permission %}

在此示例中,如果请求对象没有适当的权限(在这种情况下为some_permission),则不会呈现该块。但是,只要我将一个条件注入此块(使用{% if %}模板标记),我就会得到一个TemplateSyntaxError:

{% if_has_permission request "some_permission" %}
<div>
    <input type="text" name="sample_1">
    <label><input type="checkbox" name="enable_it" {% if isChecked %}checked="checked"{% endif %}> Enable</label>
</div>
{% endif_has_permission %}

我看到的错误是:

  

无效的块标记:'endif',预期'endblock'

如果有的话,我可以在自定义标记中允许条件表达式吗?我很确定{% if %}是我唯一需要允许的情况,尽管偶尔{% for %}也可能有用。

这是我的自定义模板代码:

@register.tag
def if_has_permission(parser, token):
    try:
        args = token.split_contents()
        tag_name, request, to_check = args[0], args[1], args[2]
        opts = None
        if(len(args) > 3):
            opts = args[3:]
    except IndexError:
        raise template.TemplateSyntaxError("Tag %r requires at least two arguments" % tag_name)

    if(not (to_check[0] == to_check[-1] and to_check[0] in ('"', "'"))):
        raise template.TemplateSyntaxError("The second argument to tag %r must be in quotes" % tag_name)

    nodelist_true = parser.parse(('endif_has_permission'),)
    parser.delete_first_token()
    return CheckPermissionNode(request, to_check[1:-1], opts, nodelist_true)

class CheckPermissionNode(template.Node):
    def __init__(self, request, to_check, opts, nodelist_true):
        self.request = template.Variable(request)
        self.to_check = to_check
        self.opts = opts
        self.nodelist_true = nodelist_true

    def render(self, context):
        rq = self.request.resolve(context)

        # Admins can always see everything
        if(rq.session['is_admin']):
            return self.nodelist_true.render(context)

        # Check to see if any of the necessary permissions are present
        hasPerm = False
        checkList = self.to_check.split('|')
        for c in checkList:
            if(c in rq.session['perms']):
                hasPerm = True
                break

        if(hasPerm):
            return self.nodelist_true.render(context)
        else:
            return ''

2 个答案:

答案 0 :(得分:1)

模板标签不像街区 - 更像是方法。你得到的错误是由于语法错误。

要实现这样的操作,只需创建一个过滤器来检查条件(就像您的标记现在正在做的那样)并返回 True False 然后使用它

    {% if request|your_filter_name:"condition" %}
        <p> do_sth </p>
    {% endif %}

使用默认的django-template if 阻止

请注意,您无法在 if 块中使用标记 - 这就是您需要将其更改为过滤的原因(通过添加register.filter代替register.tag )。什么都不会改变,但语法:

    request|your_filter:"condition"

而不是

    your_tag request "condition"

答案 1 :(得分:1)

事实证明,这确实是可能的。 if_has_permission 例程中有一个错字:

nodelist_true = parser.parse(('endif_has_permission'),)

改为:

nodelist_true = parser.parse(('endif_has_permission',))

注意逗号放错地方了! parse 函数需要一个元组。修正这个错字可以防止事情出错。

顺便说一句,我今天在遇到完全相同的问题后偶然发现了这个问题。想象一下,大约五年前,当我发现自己是最初的提问者时,我的惊讶;哈!