1. 程式人生 > >如何制作一個簡單的django權限組件

如何制作一個簡單的django權限組件

fec 直接 itl mixin model 簡單 ext reg dep

第一步:

  新建一個app

第二步:目錄結構

      技術分享圖片

  第三步:代碼如下

第一步:寫models

技術分享圖片
from django.db import models


# 定義一級菜單
class Menu(models.Model):
    title = models.CharField(max_length=32, unique=True)  # 名稱
    icon = models.CharField(max_length=32, null=True, blank=True)  # 圖標代碼:可以為空   

    def __str__(self):
        
return self.title # 定義權限 class Permission(models.Model): """ 權限表 """ title = models.CharField(verbose_name=標題, max_length=32) # 定義標題,動態生成時候,要用到 url = models.CharField(verbose_name=含正則的URL, max_length=128) # url地址 name = models.CharField(max_length=32, verbose_name=url別名
, unique=True) # 每個url的別名,唯一,且不能為空 menu = models.ForeignKey(Menu, null=True, blank=True, verbose_name=一級菜單) # 關聯的一級菜單 prent = models.ForeignKey(Permission, null=True, blank=True, verbose_name=關聯列表) # 自己關聯自己中的某個列表要使用的 def __str__(self): return self.title class Role(models.Model):
""" 角色 """ title = models.CharField(verbose_name=角色名稱, max_length=32) # 定義角色的名字 permissions = models.ManyToManyField(verbose_name=擁有的所有權限, to=Permission, blank=True) # 和權限多對多關系 def __str__(self): return self.title # 定義用戶 class UserInfo(models.Model): """ 用戶表 """ name = models.CharField(verbose_name=用戶名, max_length=32) # 賬號 password = models.CharField(verbose_name=密碼, max_length=64) # 密碼 email = models.CharField(verbose_name=郵箱, max_length=32) # 郵箱 roles = models.ManyToManyField(verbose_name=擁有的所有角色, to=Role, blank=True) # 多對多關聯角色表 def __str__(self): return self.name
models.py文件中內容

第二步:寫server文件下的init_permission.py

技術分享圖片
from django.conf import settings



# 獲取當前登錄用戶的所有權限
def init_permission(request, user):
    rbac_list = user.roles.filter(permissions__url__isnull=False).values(
        permissions__id, # 獲取權限的id
        permissions__url,# 獲取權限的url
        permissions__title,# 獲取權限的名字
        permissions__name,# 獲取權限的別名
        permissions__prent_id,# 獲取關聯列表的id
        permissions__prent__name,# 獲取關聯列表的別名
        permissions__menu_id,# 獲取一級菜單的id
        permissions__menu__title,# 獲取一級菜單的名字
        permissions__menu__icon,  # 獲取一級菜單的圖標代碼
    ).distinct() # 去重

    url_dict = {}  # 該用戶所有的權限
    menu_dic = {}  # 根據權限生成的菜單
    for i in rbac_list: # 循環所有篩選出來的內容
        """
        用每個權限的別名做key,
        value是[
            ‘url‘:權限的url,
            ‘id‘:每個權限的id,
            ‘pid‘:‘它所關聯權限的id‘,
            ‘title‘:‘它自己的標題‘,
            ‘pname‘:‘它所關聯權限的別名‘
            ]

        """
        url_dict[i[permissions__name]] = {url: i[permissions__url], 
                                            id:i[permissions__id],
                                            pid:i[permissions__prent_id],
                                            title:i[permissions__title],
                                            pname:i[permissions__prent__name],
                                            }
        # 獲取一級菜單的id
        menu_id = i.get(permissions__menu_id)
        # 判斷如果沒有一級菜單的id就重新循環
        if not menu_id:
            continue
        # 判斷一級菜單的id是否存在menu_dic這個字典裏
        # 如果存在
        if menu_id not in menu_dic:
            """
            結構:
            一級菜單id = {
            ‘title‘:一級菜單的名稱
            ‘icon‘:一級菜單的圖標代碼
            ‘children‘:[{
                
                ‘title‘:二級菜單的標題,
                ‘url‘:二級菜單的url
                ‘id‘:二級菜單的id
    
                }]}
                
            """
            menu_dic[i[permissions__menu_id]] = {
                title: i[permissions__menu__title],
                icon: i[permissions__menu__icon],
                children: [
                    {title: i[permissions__title],
                     url: i[permissions__url],
                     id:i[permissions__id]
                     }
                ]
            }
        else:
            menu_dic[i[permissions__menu_id]][children].append({title: i[permissions__title],
                                                                    url: i[permissions__url],
                                                                    id: i[permissions_id]
                                                                    })
    
    # 把篩選出來的該用戶所有權限和菜單結構全部存入到session中
    # settings.PERMISSION_SESSION_KEY和settings.MENU_SESSION_KEY:自己在自己的settings文件中設置
    request.session[settings.PERMISSION_SESSION_KEY] = url_dict
    request.session[settings.MENU_SESSION_KEY] = menu_dic
權限相關的所有代碼

第三步:寫middlewear下的rbac.py

技術分享圖片
import re
from django.conf import settings
from django.shortcuts import HttpResponse
from django.utils.deprecation import MiddlewareMixin




# 中間件
class RbacPermissionMiddleware(MiddlewareMixin):
    
    def process_request(self, request):
        # 獲取當前訪問的地址
        current_url = request.path_info
        # 循環判斷白名單,自己在settings設置自己的白名單
        for i in settings.WITER_LIST:
            if re.match(^%s$%i, current_url):
                return
        # 獲取當前用戶權限
        permissions_dict = request.session[settings.PERMISSION_SESSION_KEY]
        # 小菜單要使用
        request.breadcrumb_list=[{title:首頁,url:/}]
        # 循環判斷
        flag = False
        # 循環用戶的所有權限
        for item in permissions_dict.values():
            # 正則匹配
            if re.match(item[url], current_url):
                # 匹配成功修改flag
                flag = True
                # 獲取id,父級id,父級url別名
                id = item[id]
                pid = item[pid]
                pname = item[pname]
                # 判斷是否有父級id
                if pid:
                    # 獲取父級id,在動態生成菜單時要用
                    request.current_menu_id = pid
                    # 父級的url,title,和自己的url好和title
                    request.breadcrumb_list.extend([
                        {url:permissions_dict[pname][url],title:permissions_dict[pname][title]},
                        {url:item[url],title:item[title]},
                                                    ])
                else:
                    # 獲取自己id,在動態生成菜單時要用
                    request.current_menu_id = id
                    # 自己的url好和title
                    request.breadcrumb_list.extend([
                        {url: item[url], title: item[title]}
                    ])
                break
        # 判斷當前用戶是否有權限訪問這個頁面
        if not flag:
            return HttpResponse(你沒有此權限)
中間件的代碼

第四步:寫templatetags下的rbac.py

技術分享圖片
from django.conf import settings
from django import template
from collections import OrderedDict

register = template.Library()


# 設置左側菜單的模板組件
@register.inclusion_tag(rbac/module.html)
def show_results(request):
    # 獲取存儲菜單的字典
    menu_dic = request.session[settings.MENU_SESSION_KEY]
    # 讓字典變的有序,python3.6在一些特殊的情況下會變得無序
    order_dict = OrderedDict()
    # 循環這個字典,字典先排序
    for item in sorted(menu_dic):
        # 把這個字典裏所有內容傳入到有序字典裏
        order_dict[item] = menu_dic[item]
        # 給所有的一級菜單中都加入一個hide(隱藏)
        order_dict[item][class] = hide
        # 循環這個字典的二級菜單
        for i in order_dict[item][children]:
            # 判斷當前訪問的url的id是否是當前循環二級菜單的id
            if request.current_menu_id == i[id]:
                # 如果是的話,給他添加‘active‘和去除一級菜單的‘hide‘
                i[class] = active
                order_dict[item][class] = ‘‘
    # 把字典出入html文件裏
    return {menu_dic: order_dict}


# 設置小菜單
@register.inclusion_tag(rbac/breadcrumb.html)
def breadcrumb(request):
    # 把小菜單需要的列表傳入
    return {breadcrumb_list: request.breadcrumb_list}


# 設置過濾器
@register.filter
def has_permission(request, name):
    # 判斷傳入的url別名是否在菜單字典中
    if name in request.session.get(settings.PERMISSION_SESSION_KEY):
        return True
標簽代碼 技術分享圖片
<div class="multi-menu">
    {% for item in menu_dic.values %}
         <div class="item">
             <div class="title">
                 <span class="icon-wrap"><i class="fa {{ item.icon }}"></i></span>{{ item.title }}
             </div>
             <div class="body {{ item.class }}">
                 {% for per in item.children %}
                    <a href="{{ per.url }}" class="{{ per.class }}" >{{ per.title }}</a>
                 {% endfor %}
             </div>
         </div>
    {% endfor %}
</div>
module.html的代碼 技術分享圖片
<ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;">
    {% for item in breadcrumb_list %}
        {% if forloop.last %}
            <li class="active">{{ item.title }}</li>
            {% else %}
                <li><a href="{{ item.url }}">{{ item.title }}</a></li>
        {% endif %}
    {% endfor %}
</ol>
breadcrumb.html的代碼

第五步:admin.py中的代碼

技術分享圖片
from django.contrib import admin
from rbac import models


class PermissionAdmin(admin.ModelAdmin):
    list_display = [title, url,menu,prent,name] # 頁面要顯示的內容
    list_editable = [url,menu,prent,name]   # 可以在頁面更改的內容



admin.site.register(models.Role)
admin.site.register(models.Permission, PermissionAdmin)
admin.site.register(models.UserInfo)
admin.site.register(models.Menu)
admin.py中的代碼

有一些註釋可能寫的比較迷,直接貼圖吧

左菜單/大菜單

技術分享圖片

小菜單

技術分享圖片

簡單的組件寫完了,組件的css和js代碼根據自己設計的頁面來寫

組件的使用

第一步:

 

如何制作一個簡單的django權限組件