Django之菜單排序、路徑導航、訪問子菜單時二級菜單默認展開、權限精確到按鈕級別

一.一級菜單排序

實現思路:
在一級菜單表中加一個權重字段,根據這個字段來排序。

 weight = models.IntegerField(default=1)  # 權重 左側菜單欄根據這個來排序

那麼獲取用戶權限時就要獲取一下這個字段:

def permission(request,user_obj):
    # 登錄認證
    request.session['is_login'] = True

    # 用戶權限認證
    permissions_list = user_obj.roles.values(
        'Permissions__id',
        'Permissions__url',
        'Permissions__title',
        'Permissions__menus__weight',   # 權重
        'Permissions__menus__id',
        'Permissions__menus__title',
        'Permissions__menus__icon',

    ).distinct()
    request.session[settings.PERMISSIONS_KEY] = list(permissions_list)
	
	# 左側菜單欄權限
    menu_dict = {}
    for menu in permissions_list:
        if menu.get('Permissions__menus__id'):
            if menu.get('Permissions__menus__id') in menu_dict:
                menu_dict[menu.get('Permissions__menus__id')]['children'].append(
                    {'url': menu.get('Permissions__url'),
                     'title': menu.get('Permissions__title'),
                     }
                )
            else:
                menu_dict[menu.get('Permissions__menus__id')] = {
                    'title':menu.get('Permissions__menus__title'),   # 一級菜單
                    'icon':menu.get('Permissions__menus__icon'),     # 一級菜單icon 圖標
                    'weight': menu.get('Permissions__menus__weight'), # 權重 用來排序用
                    'children':[
                        {'url':menu.get('Permissions__url'),
                         'title':menu.get('Permissions__title'),
                         }  # 二級菜單
                    ]
                }
    request.session[settings.MENU_KEY] = menu_dict

自定義標籤中:

from django import template
from django.conf import settings
from collections import OrderedDict

register = template.Library()

@register.inclusion_tag('menu.html')
def menu(request):
    menu_dict = request.session.get(settings.MENU_KEY)
    current_path = request.path
    order_dict = OrderedDict()  # 有序字典對象
    keys = sorted(menu_dict,key=lambda x:menu_dict[x]['weight'],reverse=True)  #  1 2
    for sorts in keys:
        order_dict[sorts] = menu_dict[sorts]

數據庫中財務管理的值比銷售管理的值大:
在這裏插入圖片描述
效果:
在這裏插入圖片描述

二.保留二級菜單默認展開效果

自定義標籤中加下面這段代碼:
首先給所有的二級菜單加一個hidden效果全部收起來,如果訪問的url匹配到二級菜單的路徑就讓class值等於空,展開效果。

for key,values in order_dict.items():
    values['class'] = 'hidden'
    for i in values['children']:
        if re.match(i['url'],current_path):
            values['class'] = ''

menu.html文件中:

<div class="multi-menu">
    {% for menu_k,menu_v in menu_dict.items %}
        <div class="item">
        <div class="title"> {{ menu_v.title }}</div>
            <div class="body {{ menu_v.class }}">
                {% for ermenu in menu_v.children %}
                    <a href="{{ ermenu.url }}">{{ ermenu.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>

三.二級菜單的點擊效果

需求:點擊的二級菜單想要有選中的效果。
如果訪問的url匹配到二級菜單的路徑就給所有的二級菜單加一個值class=active。
代碼:

for key,values in order_dict.items():
    values['class'] = 'hidden'
    for i in values['children']:
        if re.match(i['url'],current_path):
            values['class'] = ''
            i['class'] = 'active'

menu.html:

<div class="multi-menu">
    {% for menu_k,menu_v in menu_dict.items %}
        <div class="item">
        <div class="title"> {{ menu_v.title }}</div>
            <div class="body {{ menu_v.class }}">
                {% for ermenu in menu_v.children %}
                    <a href="{{ ermenu.url }}" class="{{ ermenu.class }}">{{ ermenu.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>

效果:
在這裏插入圖片描述

四.二級菜單權限訪問時二級菜單默認展開

出現的問題:
點擊其他功能項時,左側菜單欄會收起。
解決思路:
在權限表中加一個字段外鍵到他自己這張表,如果是二級菜單那麼值就是None,如果不是二級菜單就記錄當前這個路徑屬於哪個二級菜單。
在這裏插入圖片描述
首先先要把parent_id和二級菜單的他自己的id寫到session中,方便後續用:

def permission(request,user_obj):
    # 登錄認證
    request.session['is_login'] = True

    # 權限認證
    permissions_list = user_obj.roles.values(
        'Permissions__id',
        'Permissions__url',
        'Permissions__title',
        'Permissions__parent_id',       # 用來記錄二級菜單的子菜單
        'Permissions__menus__weight',   # 權重
        'Permissions__menus__id',
        'Permissions__menus__title',
        'Permissions__menus__icon',

    ).distinct()
    request.session[settings.PERMISSIONS_KEY] = list(permissions_list)

    menu_dict = {}
    for menu in permissions_list:
        if menu.get('Permissions__menus__id'):
            if menu.get('Permissions__menus__id') in menu_dict:
                menu_dict[menu.get('Permissions__menus__id')]['children'].append(
                    {'url': menu.get('Permissions__url'),
                     'title': menu.get('Permissions__title'),
                     'id': menu.get('Permissions__id'),   # 當前二級菜單的id
                     }
                )
            else:
                menu_dict[menu.get('Permissions__menus__id')] = {
                    'title':menu.get('Permissions__menus__title'),   # 一級菜單
                    'icon':menu.get('Permissions__menus__icon'),     # 一級菜單icon 圖標
                    'weight': menu.get('Permissions__menus__weight'),
                    'children':[
                        {'url':menu.get('Permissions__url'),
                         'title':menu.get('Permissions__title'),
                         'id': menu.get('Permissions__id'),     # 當前二級菜單的id
                         }  # 二級菜單
                    ]
                }
    request.session[settings.MENU_KEY] = menu_dict

怎麼樣獲取到二級菜單中的parent_id呢,之前是在中間件做的路徑權限認證,可以在這裏把獲取parent_id進行記錄。

 # 獲取二級菜單的子菜單
 pid =permission_path.get('Permissions__parent_id')
 if pid:
     # 獲取到了就記錄這個子菜單的id
     request.current_id = pid
 else:
     # 如果獲取不到子菜單的id 那麼current_id就等於當前二級菜單的id
     request.current_id = permission_path.get('Permissions__id')

 return None

自定義標籤中稍作改動:

for key,values in order_dict.items():
    values['class'] = 'hidden'
    for i in values['children']:
    	# 不再用正則匹配了,這裏獲取到的是二級菜單的子菜單那麼點擊的時候也會有下面兩個效
    	# 果,如果獲取不到parent_id那麼就是當前二級菜單的id,也會有下面兩個效果,可謂是兩全其美
        if request.current_id == i.get('id'):
            values['class'] = ''
            i['class'] = 'active'

五.路徑導航-麪包屑

需求:
想做下面這種帶有路徑導航的功能
在這裏插入圖片描述
實現思路:
先往request裏面放一個列表,後續根據點擊的路勁往裏放不同的url。

request.bread_crumbs = [    # 麪包屑
    {'url':reverse('app05:index'),'title':'首頁'},
]

第一種實現方法:

# 獲取二級菜單的子菜單
pid =permission_path.get('Permissions__parent_id')

# 拿到pid之後,去權限表中查如果id等於parent_id就代表這個路徑是二級菜單下的子菜單,後面就獲取這個id的url和title
ret = models.Permission.objects.filter(pk=pid).first()
if pid:
    # 獲取到了就記錄這個子菜單的id
    request.current_id = pid

    # 二級菜單
    request.bread_crumbs.append({
        'url': ret.url,
        'title': ret.title,
    })

    # 二級菜單下的子菜單
    request.bread_crumbs.append({
        'url': None,
        'title': permission_path.get('Permissions__title'),
    })
else:
	# 這裏如果獲取不到parent_id就代表是二級菜單,往裏面加二級菜單的url和title
    request.bread_crumbs.append({
        'url':None,
        'title':permission_path.get('Permissions__title'),
    })
    # 如果獲取不到子菜單的id 那麼current_id就等於當前二級菜單的id
    request.current_id = permission_path.get('Permissions__id')

第二種實現方法:
第一種實現方法要操作數據庫,效率有點低,這裏實現另外一種方法:
實現思路:
將權限表中的每一條數據id作爲鍵,剩下的url title等作爲值,組成一個新字典,然後根據
獲取到的parent_id去查這個新字典的值。
代碼:

permissions_list = user_obj.roles.values(
    'Permissions__id',
    'Permissions__url',
    'Permissions__title',
    'Permissions__parent_id',       # 用來記錄二級菜單的子菜單
    'Permissions__menus__weight',   # 權重
    'Permissions__menus__id',
    'Permissions__menus__title',
    'Permissions__menus__icon',

).distinct()

# 將permissions_list重新組數據,之前是list類型
# 現在數據格式是:{1:{url:xx,title:xx}}
# 通過permissions_dict[parent_id][url] 來獲取子菜單的url和title
permissions_dict = {}
for permissions in permissions_list:
    permissions_dict[permissions.get('Permissions__id')] = permissions

request.session[settings.PERMISSIONS_KEY] = permissions_dict

最終的方式:

# 獲取二級菜單的子菜單
pid =permission_path.get('Permissions__parent_id')
ret = models.Permission.objects.filter(pk=pid).first()
if pid:
    # 獲取到了就記錄這個子菜單的id
    request.current_id = pid

    # 二級菜單
    # 第一種方式:
    # request.bread_crumbs.append({
    #     'url': ret.url,
    #     'title': ret.title,
    # })

    # 第二種方式:
    request.bread_crumbs.append({
        'url': permission_path_dict[str(pid)]['Permissions__url'],
        'title': permission_path_dict[str(pid)]['Permissions__title'],
    })

    # 二級菜單下的子菜單
    request.bread_crumbs.append({
        'url': None,
        'title': permission_path.get('Permissions__title'),
    })
else:
    request.bread_crumbs.append({
        'url':None,
        'title':permission_path.get('Permissions__title'),
    })
    # 如果獲取不到子菜單的id 那麼current_id就等於當前二級菜單的id
    request.current_id = permission_path.get('Permissions__id')

html中:

 {% for crumb in request.bread_crumbs %}
      {% if crumb.url %}
      <li><a href="{{ crumb.url }}">{{ crumb.title }}</a></li>
          {% else %}
          <li class="active">{{ crumb.title }}</li>
      {% endif %}
  {% endfor %}

六.權限精確到按鈕級別

需求:
沒有權限的按鈕不顯示出來。
實現思路:
在權限表中加一個字段url_name用來標識路徑別名,將url_name的值取出來放到session中,自定義一個過濾器,如果urls.py中設置的別名在session中就顯示,不在則不顯示。
代碼實現:
數據庫中加一個字段:

url_name = models.CharField(max_length=32,unique=True)

獲取url_name別名並放到session中:

url_name_list = []
url_name_list.append(menu.get('Permissions__url_name'))
request.session['url_name'] = url_name_list   # 別名

自定義過濾器:

@register.filter
def url_name_filer(name,request):
    # 路徑是否在url_name中
    if name in request.session['url_name']:
        return True
    else:
        return False

前端HTML根據返回的結果做判斷:

{% extends 'layout.html' %}
{% load mytag %}    # 加載一下自定義標籤
{% block content %}
    {% if 'customer_add'|url_name_filer:request %}
        <h1><a href="{% url 'app05:customer_add' %}">添加客戶記錄</a></h1>
    {% endif %}
    <form action="" method="post">
        {% csrf_token %}
        <table class="table table-bordered table-hover">
            <thead>
            <tr>
                <th>序號</th>
                <th>姓名</th>
                <th>年齡</th>
                <th>郵箱</th>
                <th>公司</th>
                {% if 'customer_del'|url_name_filer:request or 'customer_edit'|url_name_filer:request %}
                <th>操作</th>
                {% endif %}
            </tr>
            </thead>
            <tbody>
            {% for customer in customer_obj %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ customer.name }}</td>
                    <td>{{ customer.age }}</td>
                    <td>{{ customer.email }}</td>
                    <td>{{ customer.company }}</td>
                 {% if 'customer_del'|url_name_filer:request or 'customer_edit'|url_name_filer:request %}
                        <td>
                            {% if 'customer_edit'|url_name_filer:request %}
                            <a href="{% url 'app05:customer_edit' customer.id %}"><i class="fa fa-edit"></i></a>
                            {% endif %}
                            {% if 'customer_del'|url_name_filer:request %}
                            <a href="{% url 'app05:customer_del' customer.id %}"><i class="fa fa-remove"></i></a>
                            {% endif %}
                        </td>
                {% endif %}
                </tr>
            {% endfor %}
            </tbody>
        </table>
        <button class="btn btn-success">提交</button>
    </form>
{% endblock %}

效果:
什麼權限也沒有
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章