if..else自定义模板标记

时间:2011-10-17 09:05:09

标签: django django-templates

我正在我的Django项目中实现自定义权限应用程序,我很遗憾如何实现自定义模板标记,该标记检查登录用户对特定对象实例的权限并显示基于HTML的HTML检查的结果。

我现在拥有的是(伪代码):

{% check_permission request.user "can_edit" on article %}
    <form>...</form>
{% endcheck %}

('check_permission'是我的自定义模板标记)。

templatetag接受用户,权限和对象实例,并返回随附的HTML(表单)。目前工作正常。

然而,我想做的是:

{% if check_permission request.user "can_edit" on article %}
    <form>...</form>
{% else %}
    {{ article }}
{% endif %}

我已经阅读了the assignment tag,但我担心的是我会用此污染上下文变量空间(这意味着我可能会覆盖以前的权限上下文变量)。换句话说,由于上下文变量是在不同的层次上定义的(视图,我的中间件,现在是这个赋值模板标签),我担心可维护性。

4 个答案:

答案 0 :(得分:14)

您可以在if语句中使用模板过滤器。因此,您可以将标记重写为过滤器:

{% if request.user|check_can_edit:article %}

请注意,将不同类型的多个参数传递给过滤器很棘手,因此您可能希望每个权限使用一个过滤器,上面我使用了check_can_edit

答案 1 :(得分:14)

如果您愿意编写更多的python代码来提高模板的可读性,那么你绝对可以做到! :)

如果你想在它们上面使用变量,你需要自己解析标签内容,甚至是它所采用的参数然后解决它们。

下面实现的标签可以像这样使用:

{% load mytag %}
{% mytag True %}Hi{% else %}Hey{% endmytag %} Bro

或使用变量:

{% mytag myobject.myflag %}Hi{% else %}Hey{% endmytag %} Bro

所以,这就是我做的方式:

from django.template import Library, Node, TemplateSyntaxError

register = Library()

@register.tag
def mytag(parser, token):
    # Separating the tag name from the "test" parameter.
    try:
        tag, test = token.contents.split()
    except (ValueError, TypeError):
        raise TemplateSyntaxError(
            "'%s' tag takes two parameters" % tag)

    default_states = ['mytag', 'else']
    end_tag = 'endmytag'

    # Place to store the states and their values
    states = {}

    # Let's iterate over our context and find our tokens
    while token.contents != end_tag:
        current = token.contents
        states[current.split()[0]] = parser.parse(default_states + [end_tag])
        token = parser.next_token()

    test_var = parser.compile_filter(test)
    return MyNode(states, test_var)


class MyNode(Node):
    def __init__(self, states, test_var):
        self.states = states
        self.test_var = test_var

    def render(self, context):
        # Resolving variables passed by the user
        test_var = self.test_name.resolve(context, True)

        # Rendering the right state. You can add a function call, use a
        # library or whatever here to decide if the value is true or false.
        is_true = bool(test_var)
        return self.states[is_true and 'myvar' or 'else'].render(context)

就是这样。 HTH。

答案 2 :(得分:0)

在这种情况下,最好的解决方案是使用自定义过滤器。如果您不想为自定义标签编写长代码。另外,如果您不想复制/粘贴其他代码。 这是一个示例

  

内部模板标签

register = template.Library()
def exam_available(user, skill):
    skill = get_object_or_404(Skill, id=skill)
    return skill.exam_available(user)
register.filter('exam_available', exam_available)
  

内部模板

    {{ request.user|exam:skill.id  }}
    or
    {% if request.user|exam:skill.id  %}

由于它的主要共同点之一是在模型的自定义方法中使用request.user或任何特定的对象(id),因此过滤单个对象或用户是最简单的方法。 :)

答案 3 :(得分:0)

在Django 2中,赋值标签已替换为simple_tag(),但您可以将自定义标签结果存储为模板变量:

# I'm assuming that check_permission receives user and article,
# checks if the user can edit the article and return True or False
{% check_permission user article as permission_cleared %}
{% if permission_cleared %}
    <form>...</form>
{% else %}
    {{ article }}
{% endif %}

检查有关自定义模板标签的当前文档:https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/#simple-tags