代码之家  ›  专栏  ›  技术社区  ›  jbochi

Django动态菜单设计问题

  •  1
  • jbochi  · 技术社区  · 16 年前

    here 顺便说一句 documentation itself ,我知道我可以使用以下代码片段在模板中实现这一点:

    {% if perms.polls.can_vote %}
        <li>
            <a href="/polls/vote">Vote</a>
        </li>
    {% endif %}
    

    documentation 详情如下:

    from django.contrib.auth.decorators import permission_required
    
    def my_view(request):
        # ...
    my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view)
    

    这不是违背了干涸的原则吗?难道没有办法只在一个地方定义每个url所需的权限吗?也许在URL.py中?

    2 回复  |  直到 9 年前
        1
  •  2
  •   Michał Marczyk    16 年前

    编辑:

    在受到俱乐部会员的好意打击后(见下面OP的评论),我发现我能比以前看到更多的问题。抱歉花了这么长时间。无论如何:

    这种模板适合你吗?

    {% for mi in dyn_menu_items %}
      {% if mi.authorised %}
         <a href={{ mi.url }}>{{ mi.title }}</a>
      {% endif %}
    {% endfor %}
    

    要在Python端实现这一点,可以使用 RequestContext 在视图中,使用自定义上下文处理器设置 dyn_menu_items 适当的变量。如果需要一些背景信息,则 Advanced Templates 请求上下文 render_to_response

    此外,我想在这一点上,将负责站点锁定部分的视图功能放在某个列表中可能会很有用:

    _dyn_menu_items = [(url1, view1, title1, perm1), ...]
    

    那你就可以 map prepare_pattern 和 prepare_menu_item

    def prepare_pattern(menu_item):
        url1, view, title, perm = menu_item
        pattern = PREPARE_URLCONF_ENTRY_SOMEHOW(...) # fill in as appropriate
        return pattern
    
    def prepare_menu_item(menu_item):
        url, view, title, perm = menu_item
        mi = PREPARE_THE_BIT_FOR_REQUESTCONTEXT(...) # as above
        return mi
    

    当然,这些可以组合成一个函数,但不是每个人都会发现结果更具可读性。。。总之,输出 map(prepare_menu_item, _dyn_menu_items) 将需要一个字典,由一个有用的上下文处理器传递给您的视图(计算出来,这里有点乏味,我留给您;-),鉴于 map(prepare_pattern, _dyn_menu_items) ,我们就叫它吧 dyn_menu_patterns patterns('', *dyn_menu_patterns)

    我希望这是有意义的,是一些帮助。。。

    预编辑答案:

    根据您的简短描述,我不确定哪种解决方案最适合您。。。但是如果 permission_required snippet可以满足您的需要,只是还不够干,不如自己滚动包装纸:

    def ask_to_login(perm, view):
        return permission_required(perm, login_url='/loginpage/', view)
    

    你可以把它放在任何地方,包括URLconf。然后你可以替换所有提到的 '/loginpage/'

    当然,这些观点仍然需要明确包装;如果这让你感到困扰,你可以试着 ask_to_login

        2
  •  1
  •   Greatlemer    16 年前

    http://code.google.com/p/greatlemers-django-tools/ 在你的评论中,所以我想我应该插手。

    该项目仍然处于活动状态(尽管它现在稍微在backburner上),但我不确定它是否像您所追求的那样干燥。您仍然需要指定两次权限,一次在菜单项的模型对象中,一次在视图中。但是,这并不一定是坏事,因为您在菜单项上定义的权限可能与在视图上定义的权限略有不同。

    如果你想在一个地方做任何事情,我可能会建议在URL.py中使用一个实用函数的组合,它可以为视图添加限制,同时也可以将所述限制存储在某个地方,以便与一个特殊的模板标记一起使用。我想它可能看起来像这样。

    # Stored in a file named access_check_utils.py say.
    from django.conf.urls.defaults import url
    from django.core.urlresolvers import get_callable
    from django.contrib.auth.decorators import permission_required
    
    access_checked_urls = {}
    
    def access_checked_url(regex, view, kwargs=None, name=None, prefix='', perms=None, login_url=None):
        if perms is None:
            perms = []
        callback = None
        if callable(view):
            callback = view
        elif isinstance(view, basestring):
            if prefix:
                view_path = "%s.%s" % (prefix, view)
            else:
                view_path = view
            try:
                callback = get_callable(view_path)
            except:
                callback = None
        if callback is not None:
            # Add all the permissions
            for perm in perms:
                callback = permission_required(perm, login_url=login_url)(callback)
            if name is not None:
                access_checked_urls[name] = perms
        else:
            callback = view
        return url(regex, callback, kwargs=kwargs, name=name, prefix=prefix)
    

    这应该适用于url.py中所需的pit,调用方式与使用普通url相同,但添加了perms和login_url参数(perms应该是所有相关参数的列表)。

    # In a templatetag folder somewhere
    from django import template
    from django.core.urlresolvers import
    
    # This needs to point to the right place.
    from access_check_utils import access_checked_urls
    
    register = template.Library()
    
    @register.inclusion_tag("access_checked_link.html", takes_context=True)
    def access_checked_link(context, title, url, *args, **kwargs):
        perms = access_checked_urls.get(url, [])
        if not perms:
           allowed = True
        else:
           allowed = context.request.user.has_perms(perms)
        return { 'allowed': allowed,
                 'url': reverse(url, *args, **kwargs),
                 'title': title }
    

    这将有一个关联的模板文件,如:

    {% if allowed %}<a href="{{ url }}">{{ title }}</a>{% endif %}
    

    希望这能有所帮助。

    --