1. 程式人生 > >Django - 許可權(3)- 動態顯示二級選單

Django - 許可權(3)- 動態顯示二級選單

一、動態顯示二級選單

  上篇隨筆中,我們實現了動態顯示一級選單,現在考慮這樣一種情況,使用者的選單許可權比較多,這個時候全部並列展現在左側選單就不合適了,所以,現在有這樣一個需求,即把使用者的選單許可權分類,劃分成二級選單,動態顯示在左側選單,解決方案如下:

1、修改許可權表結構

  (1)分析需求,要求左側選單如下顯示:

    客戶管理:

      客戶列表

    賬單管理:

      賬單列表

  (2)修改rbac下的models.py,修改後程式碼如下:

from django.db import models

class User(models.Model):
    
""" 使用者表 """ name = models.CharField(verbose_name='使用者名稱', max_length=32) password = models.CharField(verbose_name='密碼', max_length=32) roles = models.ManyToManyField(verbose_name='擁有的所有角色', to='Role') def __str__(self): return self.name class Role(models.Model):
""" 角色表 """ title = models.CharField(verbose_name='角色名稱', max_length=32) permissions = models.ManyToManyField(verbose_name='擁有的所有許可權', to='Permission') def __str__(self): return self.title class Permission(models.Model): # 建立與選單類的關聯,去掉is_menu和icon """ 許可權表
""" url = models.CharField(verbose_name='含正則的URL', max_length=32) title = models.CharField(verbose_name='標題', max_length=32) menu = models.ForeignKey(verbose_name='所屬選單', to="Menu", on_delete=models.CASCADE, null=True) def __str__(self): return self.title class Menu(models.Model): # 新增一個選單表 title = models.CharField(max_length=32, verbose_name='選單') icon = models.CharField(max_length=32, verbose_name='圖示', null=True, blank=True)

2、注入session(重點是構建資料結構),setsession.py中程式碼修改如下:

def initial_session(user_obj, request):
    """
    將當前登入人的所有許可權url列表和自己構建的所有選單許可權字典注入session
    :param user_obj: 當前登入使用者物件
    :param request: 請求物件HttpRequest
    """
    # 查詢當前登入人的所有許可權列表
    ret = Role.objects.filter(user=user_obj).values('permissions__url',
                                                    'permissions__title',
                                            'permissions__menu__title',
                                                    'permissions__menu__icon',
                                                    'permissions__menu_id').distinct()
    permission_list = []
    permission_menu_dict = {}
    for item in ret:
        # 獲取使用者許可權列表用於中介軟體中許可權校驗
        permission_list.append(item['permissions__url'])
        menu_pk = item['permissions__menu__id']
        if menu_pk:
            if menu_pk not in permission_menu_dict:
                permission_menu_dict[menu_pk] = {
                    "menu_title": item["permissions__menu__title"],
                    "menu_icon": item["permissions__menu__icon"],
                    "children": [
                        {
                            "title": item["permissions__title"],
                            "url": item["permissions__url"],
                        }
                    ],
                }
            else:
                permission_menu_dict[menu_pk]["children"].append({
                    "title": item["permissions__title"],
                    "url": item["permissions__url"],
                })
    print('許可權列表', permission_list)
    print('選單許可權', permission_menu_dict)
    # 將當前登入人的許可權列表注入session中
    request.session['permission_list'] = permission_list
    # 將當前登入人的選單許可權字典注入session中
    request.session['permission_menu_list'] = permission_menu_dict

3、從session中取出選單許可權資訊,修改my_tags.py檔案,程式碼如下:

from django.template import Library
register =Library()

@register.inclusion_tag("menu.html")
def get_menu_styles(request):
    permission_menu_dict = request.session.get("permission_menu_dict")
    return {"permission_menu_dict": permission_menu_dict}

4、渲染頁面,修改menu.html檔案,程式碼如下:

<div class="multi-menu">
    {% for item in permission_menu_dict.values %}
        <div class="item">
            <div class="title">
                <i class="{{ item.menu_icon }}"></i>{{ item.menu_title }}
            </div>
            <div class="body">
                {% for foo in item.children %}
                    <a href="{{ foo.url }}">{{ foo.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>

  到此,二級選單已經渲染到頁面中了,樣式或者其他js效果就靠你的前端技術了!

二、補充知識點

1、DATABASES的使用

  我們知道django專案使用資料庫要在settings.py中通過設定DATABASES給專案配置資料庫引擎,我們之前都是給專案設定成MySQL或者django預設的sqlite3資料庫,大家知道一個專案可以有多個應用,並且事實也是如此的,每個專案下也會自己的模型類,按照之前的做法,在定義了資料庫引擎之後做資料庫遷移,那麼每個app下的資料庫都使用settings中指定的資料庫了,但是你可能會有這樣的需求,就是不同的應用使用不同的資料庫,該如何做呢?沒錯,也是設定DATABASES,方式如下:

DATABASES = {
    'default': {   # 下面沒有指定的都使用default下的資料庫引擎
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'app01':{    # app01使用mysql資料庫引擎
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'bms',   # 要連線的資料庫,連線前需要建立好
        'USER': 'root',  # 連線資料庫的使用者名稱
        'PASSWORD': '',  # 連線資料庫的密碼
        'HOST': '127.0.0.1',  # 連線主機,預設本機
        'PORT': 3306   #  埠 預設3306
    }
}

2、ForeignKey的引數db_constraint解釋

  在學習資料庫時,我們通過定義外來鍵使兩個表建立連線和約束,但有時我們需要只建立連線,不建立約束,也就是通過在表中建立另一個表的id,不設定foreignkey約束。

  Django的ForeignKey也為我們想好了這兩種情況:

    (1)db_constraint = True 表示兩個表之間既建立了連線又有約束,並支援ORM語法查詢;

    (2)db_constraint = False 表示兩個表之間只建立了連線,沒有建立約束,並支援ORM語法查詢;

  注意:當然你可能會想到能否將ForeignKey改為一個IntegerField,通過定義IntegerField欄位的值來與另一個表建立聯絡,這種方法也沒錯,但是這樣就不能使用ORM語法查詢,也就享受不到ORM查詢的方便,為開發造成了困難,所以不推薦這樣做!