如何为访问控制编写 Django 模板标签?
Posted
技术标签:
【中文标题】如何为访问控制编写 Django 模板标签?【英文标题】:How do I write a Django template tag for access control? 【发布时间】:2011-04-15 23:56:22 【问题描述】:我试图创建一个简单的 Django 模板标签来显示或隐藏我网站上提交的评论旁边的“删除”链接,但徒劳无功。
简而言之,我想将评论对象传递给模板标签,确定当前登录的用户是否有权删除评论,然后显示或不显示链接。
我的模板中的用法是这样的:
% load access_tags %
% if_authorized comment %
<a href="% url delete_comment comment.id %">Delete</a>
% endif_authorized %
请放心,如果用户有权删除评论,我也会检查相应的视图。
这种类型的标签有特定的名称吗?如果确实如此,它肯定会帮助我进行 Google 搜索。感谢您的帮助!
更新 1:
根据我的网站的运作方式,可能有两个人有权删除评论:1) 评论创建者和 2) 留下评论的帖子的所有者。因此,我需要根据评论确定是否存在这些条件之一。
我认为我不能使用 Django 的内置权限系统之类的东西,因为它要求“根据对象类型全局设置权限,而不是针对特定对象实例”。
在我的例子中,用户“Bob”可能有权删除评论(如果他写了评论或评论在他创建的帖子上),但他也可能不被允许删除它(如果他正在查看评论别人的帖子)。
更新 2:
看来你不能将对象传递给模板标签,只能传递字符串:“虽然你可以使用 token.split_contents() 将任意数量的参数传递给模板标签,但参数都被解包为字符串字面意思。”我想我会传递有问题的评论对象的 id 并将其拉入标签中。
我错了,只需要访问传入的对象,例如:
self.comment.resolve(context).user
对比
self.comment.user
【问题讨论】:
【参考方案1】:好的,我就是这样做的……
标签在模板中是这样使用的:
% load access_tags %
% if_authorized comment.user object.user user %
<a href="% url delete_comment comment.id %">Delete</a>
% endif_authorized %
模板标签文件名为“access_tag.py”,位于我的应用程序的“templatetags”目录中。这是“access_tag.py”的内容:
from django.template import Node, NodeList, TemplateSyntaxError
from django.template import Library, Variable, VariableDoesNotExist
register = Library()
def do_if_authorized(parser, token):
"""
Outputs the contents of the block if the 'comment owner' or the
'page owner' is also the 'authenticated user'. As well, you can use
an % else % tag to show text if the match fails.
Takes three parameters:
1) the comment owner
2) the page owner
3) the current authenticated user
"""
bits = token.contents.split()
if len(bits) != 4:
raise TemplateSyntaxError("%s tag takes three arguments: \
1) the comment owner \
2) the page owner \
3) the current authenticated user" % bits[0])
nodelist_true = parser.parse(('else', 'endif_authorized'))
token = parser.next_token()
if token.contents == 'else':
nodelist_false = parser.parse(('endif_authorized',))
parser.delete_first_token()
else:
nodelist_false = NodeList()
return IfAuthorizedNode(bits[1], bits[2], bits[3], nodelist_true, nodelist_false)
class IfAuthorizedNode(Node):
def __init__(self, comment_owner, page_owner, authenticated_user, nodelist_true, nodelist_false):
self.nodelist_true = nodelist_true
self.nodelist_false = nodelist_false
self.comment_owner = Variable(comment_owner)
self.page_owner = Variable(page_owner)
self.authenticated_user = Variable(authenticated_user)
def render(self, context):
try:
comment_owner = self.comment_owner.resolve(context)
page_owner = self.page_owner.resolve(context)
authenticated_user = self.authenticated_user.resolve(context)
except VariableDoesNotExist:
return ''
if comment_owner == authenticated_user or page_owner == authenticated_user:
return self.nodelist_true.render(context)
else:
return self.nodelist_false.render(context)
register.tag('if_authorized', do_if_authorized)
完成。最后,只使用内置的 % if % 标签来进行比较会很容易,但是由于我还有其他的每个对象的授权要做,所以我将继续构建这些自定义“访问标签”。另外,模板代码看起来更整洁:)
【讨论】:
很酷的解决方案,我对其进行了调整,以便您可以检查用户权限。还可以嵌套,非常实用!谢谢【参考方案2】:已经存在一个旨在做你想做的事情的项目。
django-authority 允许对模板中的权限进行细粒度控制。
Django 1.2 在模板中也包含用户 permissions。
【讨论】:
谢谢尼克,请参阅上面的更新,了解为什么 Django 的内置权限在我的情况下可能不起作用。乍一看,使用完整的应用程序似乎有点矫枉过正,但我还是会检查一下。谢谢你的回答。【参考方案3】:这个怎么样...创建一个writes a variable in the context 的自定义标签,然后使用% if %
测试该变量
应该是这样的:
% check_access comment %
% if has_access %
<a href="% url delete_comment comment.id %">Delete</a>
% endif %
当然,“check_access”标签会在上下文中写入“has_access”。
祝你好运
【讨论】:
如果页面上有 10 个 cmets 登录用户对 3 具有删除权限,这将如何工作。“has_access”不会继续覆盖并最终设置为最后一个值? 好吧,你只需要在每条评论上调用 check _access ......但你已经找到了你的解决方案 =) F'm总是惊讶于这样一个简单的测试如何变得如此困难在 django 中做...这就是为什么 php 永远不会死! 感谢欣慰,感谢您的帮助。以上是关于如何为访问控制编写 Django 模板标签?的主要内容,如果未能解决你的问题,请参考以下文章
如何为其他模板的表单显示和提交编写基于 Django 类的视图?