Django动态菜单设计问题
我想根据用户权限创建动态菜单。正如此处和文档本身,我知道我可以使用以下代码片段在模板中实现此目的:
{% if perms.polls.can_vote %}
<li>
<a href="/polls/vote">Vote</a>
</li>
{% endif %}
但问题是出于安全原因,我也想限制对视图的访问。我在 文档如下:
from django.contrib.auth.decorators import permission_required
def my_view(request):
# ...
my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view)
这不是违反DRY原则吗?难道没有一种方法可以只在一个地方定义每个 url 所需的权限吗?也许在 urls.py 中?
I want to create dynamic menus according to user permissions. As was already discussed here and by the the documentation itself, I know that I can achieve this in the templates using the following snippet:
{% if perms.polls.can_vote %}
<li>
<a href="/polls/vote">Vote</a>
</li>
{% endif %}
But the problem is that for security reasons I want to limit the access to the views too. The snippet that I found in the documentation is the following:
from django.contrib.auth.decorators import permission_required
def my_view(request):
# ...
my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view)
Isn't this against DRY principle? Isn't there a way to define only in one place what is the permission needed for each url? Perhaps in urls.py?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
编辑:(请参阅帖子末尾的答案原文以及最初的简单想法。)
在被一个线索击中之后(请参阅下面OP的评论),我发现我可以看到更多比以前更能解决问题。抱歉花了这么长时间。无论如何:
这种模板适合您吗?
要在 Python 端实现此功能,您可以在视图中使用
RequestContext
,并通过自定义上下文处理器适当设置dyn_menu_items
变量。如果需要一些背景信息,Django Book 的 高级模板 章节介绍了RequestContext
,展示了如何将它与render_to_response
一起使用(有点重要:-))等。另外,我想在这一点上,将负责锁定的视图函数可能很有用将网站的各个部分放在某个列表中:
然后您可以在该列表中
映射
几个函数,例如prepare_pattern
和prepare_menu_item
,它的工作原理大致如下:当然,这些可以组合成一个函数,但并不是每个人都会发现结果更具可读性......无论如何,
map(prepare_menu_item, _dyn_menu_items) 的输出需要成为一本字典,由有用的上下文处理器传递到您的视图(其中的计算,这里有点乏味,我将留给您;-)),而
map( prepare_pattern, _dyn_menu_items)
,我们称之为dyn_menu_patterns
,将在patterns('', *dyn_menu_patterns)
中使用,并在您的URLconf中使用。我希望这有意义并且有一些帮助...
预编辑答案:
根据您的简短描述,我不确定哪种解决方案最适合您...但是如果
permission_required
代码片段可以实现您想要的功能,只是不够简单,如何滚动您自己的包装器:您可以将其放在任何地方,包括在 URLconf 中。然后,您可以将所有提到的
'/loginpage/'
替换为对 URL 文件顶部定义的变量的引用,这样您就可以得到一个仅提及实际登录 URL 的解决方案,对于所述 URL 的仅一处更新,您是否必须移动它。 :-)当然,视图仍然需要显式包装;如果这让您烦恼,您可以尝试将
ask_to_login
制作为装饰器,以便在定义站点轻松包装。 (但也许最好不要这样做,以免您强迫自己从装饰器下挖掘视图,以防将来某个时候需要它们未经装饰。)EDIT: (See end of post for the original text of the answer with the initial, simple idea.)
After being kindly stricken with a cluebat (see the OP's comment below), I find I can see more to the problem than before. Sorry it took so long. Anyway:
Would this kind of template be alright for you?
To make this work on the Python side, you could use
RequestContext
in your views with a custom context processor setting thedyn_menu_items
variable appropriately. In case some background information is required, the Advanced Templates chapter of the Django Book introducesRequestContext
, shows how to use it withrender_to_response
(kinda important :-)) etc.Also, I guess at this point it could be useful to put the view functions responsible for the locked-up sections of your site in a list somewhere:
Then you could
map
a couple of functions, sayprepare_pattern
andprepare_menu_item
across that list, having it work roughly like so:These could be combined into a single function, of course, but not everybody would find the result more readable... Anyway, the output of
map(prepare_menu_item, _dyn_menu_items)
would need to be a dictionary to be passed to your views by a helpful context processor (the figuring out of which, it being the slightly tedious bit here, I'll leave to you ;-)), whereas the output ofmap(prepare_pattern, _dyn_menu_items)
, let's call itdyn_menu_patterns
, would be used inpatterns('', *dyn_menu_patterns)
, to be used in your URLconf.I hope this makes sense and is of some help...
THE PRE-EDIT ANSWER:
Based on your short description, I'm not sure what solution would be best for you... But if the
permission_required
snippet does what you want, just not DRY-ly enough, how about rolling your own wrapper:You could put this anywhere, including in URLconf. Then you could replace all mentions of
'/loginpage/'
with reference to a variable defined towards the top of your URLs file and you'd have yourself a solution with a single mention of the actual login URL, for one-place-only update of said URL should you have to move it around. :-)Of course the views would still need to be wrapped explicitly; if that bothers you, you could try to make
ask_to_login
into a decorator for easy wrapping at the definition site. (But perhaps it's really best not to do it, lest you force yourself to dig your views from under the decorator in case you need them undecorated at some point in the future.)我知道这个问题是几周前提出的,但您提到了 http ://code.google.com/p/greatlemers-django-tools/ 在你的一条评论中,所以我想我应该参与其中。
该项目仍然活跃(尽管目前稍微处于次要地位) )但我不确定它是否像你所追求的那样干燥。您仍然需要指定两次权限,一次在菜单项的模型对象中,一次在视图中。但这不一定是坏事,因为您在菜单项上定义的权限可能与视图上的权限略有不同。
如果您想在一个地方完成所有操作,我可能会建议在 urls.py 中使用实用函数的组合,它可以向视图添加限制,同时还将所述限制存储在某处以与特殊模板标记一起使用。我想它可能看起来像这样。
这应该适用于 urls.py 中所需的坑,调用方式与普通 url 相同,但添加了 perms 和 login_url 参数(perms 应该是所有相关参数的列表)。
这将有一个关联的模板文件,例如:
我还没有对此进行充分测试,但它应该可以工作(或者至少是应该工作的东西的良好基础)。我什至可能会考虑将类似的内容添加到 gdt_nav 中,使其检查这些基本权限(如果存在),然后检查是否添加了任何额外权限。
希望这对您有所帮助。
——G
I'm aware this question was asked a couple of weeks ago now, but you mentioned http://code.google.com/p/greatlemers-django-tools/ in one of your comments so I thought I'd chip in.
The project is still active (although it's slightly on the backburner at the moment) but I'm not sure if it is as DRY as you're after. You would still have to specify permissions twice, once in the model object for the menu item and once on the view. This isn't necessarily a bad thing however as the permissions that you define on the menu item may be slightly different from those on the view.
If you wanted to do everything in one place I'd probably suggest a combination of a utility function for use in urls.py that can add restrictions to a view whilst also storing said restriction somewhere for use with a special template tag. I'd imagine it may look something like this.
That should work for the pit needed in urls.py called the same way as you would with a normal url but with the added perms and login_url parameters (perms should be a list of all the relevant ones).
This would have an associated template file like:
I've not tested this fully, but it should work (or at least be a good basis for something that should work). I'll probably even look to adding something like this into gdt_nav allowing it to check for these base permissions if they exist, and then checking for any extras added.
Hope this is of some help.
--
G