if..else 自定义模板标签
Posted
技术标签:
【中文标题】if..else 自定义模板标签【英文标题】:if..else custom template tag 【发布时间】:2011-12-09 03:26:56 【问题描述】:我正在我的 Django 项目中实现一个自定义权限应用程序,但我不知道如何实现一个自定义模板标签,该标签检查登录用户对特定对象实例的权限并显示一段基于检查结果。
我现在拥有的是(伪代码):
% check_permission request.user "can_edit" on article %
<form>...</form>
% endcheck %
('check_permission' 是我的自定义模板标签)。
模板标签接受用户、权限和对象实例,并返回包含的 html(表单)。这目前工作正常。
然而,我想做的是:
% if check_permission request.user "can_edit" on article %
<form>...</form>
% else %
article
% endif %
我读过the assignment tag,但我担心我会用它污染上下文变量空间(这意味着我可能会覆盖以前的权限上下文变量)。换句话说,由于上下文变量是在不同级别定义的(在我的例子中是视图、中间件,现在是这个分配模板标签),我担心可维护性。
【问题讨论】:
【参考方案1】:您可以在 if 语句中使用模板过滤器。所以你可以将你的标签重写为过滤器:
% if request.user|check_can_edit:article %
请注意,将多个不同类型的参数传递给过滤器很棘手,因此您可能希望每个权限使用一个过滤器,上面我使用了check_can_edit
。
【讨论】:
谢谢,过滤器确实是一种选择。然而,我预见到不同的权限(不仅仅是实例上的基本 CRUD,还有一些非常具体的权限),这意味着我必须创建等量的自定义模板过滤器。也许我应该重新考虑我的自定义权限模型。如果您说将多个参数传递给过滤器很棘手,您的意思是可能吗?我以为不是,所以你能澄清一下吗? 对未来访问者的更新:我想我会尝试使用链式过滤器解决它(例如 request.user|has_permission:"entries.entry.can_edit,"|has_permission_on:article
。自定义 has_permission 模板过滤器返回用户和所需的权限,然后 has_permission_on 采用这些值,根据文章变量检查它们并返回 True 或 False。
@LaundroMat 你有没有完成你的链式过滤器解决方案?如果是这样,您可以分享它作为答案吗?谢谢!
@StephenGTuggy 我已经搜索了我的项目,但找不到任何东西......我猜它是(又一个)废弃项目的一部分。很抱歉,我不能再提供任何帮助了。【参考方案2】:
如果您愿意多写几行 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。
【讨论】:
【参考方案3】:在my_tags.py
内
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def make_my_variable_true(context):
context['my_variable'] = True
return '' # without this you'll get a "None" in your html
在my_template.html
内
% load my_tags %
% make_my_variable_true %
% if my_variable %foo% endif %
【讨论】:
【参考方案4】:在这种情况下,最好的解决方案是使用自定义过滤器。如果您不想为自定义标签编写长代码。此外,如果您不想复制/粘贴其他代码。 这是一个例子
模板标签内
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),因此过滤单个对象或用户是完成它的最简单方法。 :)
【讨论】:
【参考方案5】:在 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
【讨论】:
以上是关于if..else 自定义模板标签的主要内容,如果未能解决你的问题,请参考以下文章