我正在我的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,但我担心的是我会用此污染上下文变量空间(这意味着我可能会覆盖以前的权限上下文变量)。换句话说,由于上下文变量是在不同的层次上定义的(视图,我的中间件,现在是这个赋值模板标签),我担心可维护性。
答案 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