ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

django与layui的结合尝试5:权限管理(2)

2021-06-16 16:51:46  阅读:160  来源: 互联网

标签:菜单 layui self ele item menu django 权限 id


接上篇:与layui的结合

首先要了解下layui目录的json格式:

{
  "homeInfo": {
    "title": "首页",
    "href": "/static/page/welcome-1.html?t=1"
  },
  "logoInfo": {
    "title": "LAYUI MINI",
    "image": "/static/images/logo.png",
    "href": ""
  },
  "menuInfo": [
    {
      "title": "常规管理",
      "icon": "fa fa-address-book",
      "href": "",
      "target": "_self",
      "child": []
      }
    ]
  }

其实结构跟上篇权限的目录结构一样,差别只在于个别字段,对此修改page表和menu表的字段结构,并赋值

model:

class Menu(models.Model):
    title = models.CharField(max_length=32)
    href = models.CharField(max_length=64,blank=True)
    icon = models.CharField(max_length=32,blank=True)
    target = models.CharField(max_length=32, default="_self")
    father_menu=models.ForeignKey("Menu",null=True,blank=True,on_delete=models.DO_NOTHING)
    class Meta:
        verbose_name_plural = "菜单表"
    def __str__(self):
        return  self.title

class Pages(models.Model):
    target=models.CharField(max_length=32,default="_self")
    icon=models.CharField(max_length=32,blank=True)
    page = models.CharField(max_length=32)
    belong_menu = models.ForeignKey(Menu,on_delete=models.CASCADE)
    def __str__(self):
        return  self.page

由上篇的逻辑处理思想,生成新的pemissionControl.py:


from database.model.permission import *

class pemissionControl(object):

    def __init__(self,user="default"):
        self.user=user
        self.PemissionDict={}
        self.MenuDict={}
        self.LayuiMenuDict={}
        self.LayuiLastMenu={
                "homeInfo": {
                    "title": "首页",
                    "href": "/static/page/welcome-1.html?t=1"
                },
                "logoInfo": {
                    "title": "LAYUI MINI",
                    "image": "/static/images/logo.png",
                    "href": ""
                },
                "menuInfo": []
            }
    def getPemissionDict(self):
        user=User.objects.filter(user_name=self.user).first()
        # 一个用户多角色
        role=Roles.objects.filter(user2role__user=user)
        page_action_obj=list(Role2Page2Actions.objects.filter(role__in=role).distinct().values_list("page_action__page__page","page_action__action__code"))
        # 对权限列表进行判断,如果没有键值就生成列表赋值,否则追加到列表后面
        # 最终字典格式: {'index': ['put', 'get'], 'test.html': ['get']}
        for item in page_action_obj:
            if self.PemissionDict.get(item[0]):
                if self.PemissionDict[item[0]].count(item[1]) == 0:  # 列表去重
                    self.PemissionDict[item[0]].append(item[1])
            else:
                self.PemissionDict[item[0]] = [item[1]]
        return self.PemissionDict

    def createMenuEle(self,menu_id,menu_str,parent_id):
        ele_dict = {
           "menu_id": menu_id,
             "title": menu_str,
         "parent_id": parent_id,
             "child": []
        }
        return ele_dict

    def createPageEle(self,item):
        ele_dict = {
          "title": item,
          "url":""
        }
        return ele_dict


    def InitMenuDict(self):
        # 生成菜单
        # 理论上应该根据菜单多次查找父级菜单,但是那样变成数据库多次操作
        # 因为菜单数量不多,一次取出全部,再根据对象操作更为高效
        menu_obj=Menu.objects.all().values_list("id","title","father_menu")
        for item in menu_obj:
            menu_ele= self.createMenuEle(item[0],item[1],item[2])
            self.MenuDict[str(item[0])]=menu_ele
        return self.MenuDict


    def PageHangToMenu(self):
        # 权限列表的key为页面值,所以可以用keys取有权访问的页面
        PemissionDict=self.getPemissionDict()
        self.InitMenuDict()
        for item in PemissionDict.keys():
            item_ele=self.createPageEle(item)
            MenuPage_obj=list(Menu2Page.objects.filter(page__page=item).values("menu_id"))
            for MenuPage_ele in MenuPage_obj:
                self.MenuDict[str(MenuPage_ele["menu_id"])]["child"].append(item_ele)
        return self.MenuDict

    def creatMenu(self):
        MenuDict=self.PageHangToMenu()
        menu_obj = list(Menu.objects.all().values("id", "father_menu"))
        # 菜单的挂载最新想到的逻辑是从生成的字典中pop子菜单id加入父菜单的child中
        # 但是这样不确定父菜单是不是别的子菜单,如果是,父菜单先挂载后,子菜单会找不到已经被挂载的父菜单
        # 所以就不pop子菜单,而是全部挂载后,再判断菜单节点的child是否为空,从中剔除
        # 而能这样做的原因在于,python对象是同一片内存区域,当你挂载的时候,它并不重新生成对象
        # 所以不会出现子挂父,父还要挂爷的情况
        # 但是还要记录挂载的子菜单id,没挂载过的就是根id,据此删除多余的菜单
        sonId = []
        for menu_ele in menu_obj:
            if menu_ele["father_menu"] :
                sonId.append(menu_ele['id'])
                MenuDict[str(menu_ele["father_menu"])]["child"].append(MenuDict[str(menu_ele["id"])])

        for menu_ele in list(MenuDict.keys()):
            if not MenuDict[menu_ele].get("child"):
                del MenuDict[menu_ele]
            elif int(menu_ele) in sonId:
                del MenuDict[menu_ele]
        return MenuDict
################# layui ###################################
    def createLayuiMenuEle(self,menu_id,menu_str,parent_id,icon,target):
        ele_dict = {
           "menu_id": menu_id,
           "title"  : menu_str,
         "parent_id": parent_id,
             "child": [],
            "icon"  : icon,
            "target": target
        }
        return ele_dict

    def createLayuiPageEle(self,page,target,icon):
        ele_dict = {
        "target"  : target,
          "icon"  : icon ,
          "href"  : page,
        }
        return ele_dict
    def InitLayuiMenuDict(self):
        # 生成菜单
        # 理论上应该根据菜单多次查找父级菜单,但是那样变成数据库多次操作
        # 因为菜单数量不多,一次取出全部,再根据对象操作更为高效
        menu_obj=Menu.objects.all().values_list("id","title","father_menu","icon","target")
        for item in menu_obj:
            menu_ele= self.createLayuiMenuEle(item[0],item[1],item[2],item[3],item[4])
            self.LayuiMenuDict[str(item[0])]=menu_ele
        return self.LayuiMenuDict

    def LayuiPageHangToMenu(self):
        # Layui最后一个菜单只有一个页面,不存在多个页面问题,所以直接用字典update,而不用列表的append
        PemissionDict=self.getPemissionDict()
        self.InitLayuiMenuDict()
        page_ele=Pages.objects.filter(page__in=PemissionDict.keys()).values_list("page","target","icon")
        for item in page_ele:
            item_ele=self.createLayuiPageEle(*item)  # 元组展开用*,字典展开用 **
            MenuPage_obj=list(Menu2Page.objects.filter(page__page=item[0]).values("menu_id"))
            for MenuPage_ele in MenuPage_obj:
                self.LayuiMenuDict[str(MenuPage_ele["menu_id"])].update(item_ele)
        return self.LayuiMenuDict

    def creatLayuiMenu(self):
        LayuiMenuDict=self.LayuiPageHangToMenu()
        menu_obj = list(Menu.objects.all().values("id", "father_menu"))
        sonId=[]
        for menu_ele in menu_obj:
            if menu_ele["father_menu"] :
                sonId.append(menu_ele['id'])
                LayuiMenuDict[str(menu_ele["father_menu"])]["child"].append(LayuiMenuDict[str(menu_ele["id"])])

        for menu_ele in list(LayuiMenuDict.keys()):
            if not LayuiMenuDict[menu_ele].get("child"):
                del LayuiMenuDict[menu_ele]
            elif int(menu_ele) in sonId:
                del LayuiMenuDict[menu_ele]
        # 去掉id,做成列表加到默认的Menuinfo
        for item in LayuiMenuDict:
            self.LayuiLastMenu["menuInfo"].append(LayuiMenuDict[item])
        return self.LayuiLastMenu

    def creatLayuiSimpleMenu(self):
        LayuiMenuDict=self.LayuiPageHangToMenu()
        menu_obj = list(Menu.objects.all().values("id", "father_menu"))
        # 不生成的菜单有两个特性:
        #  1.不是挂载页面的菜单
        #  2.不是别的菜单的父菜单
        # 据此,可以判断id是否在这个范围,然后不做挂载处理,直接continue
        useInMenuId=list(Menu.objects.all().values_list("father_menu",flat=True))
        useInPageId=list(Pages.objects.all().values_list("belong_menu",flat=True))
        sonId=[]
        useInMenuId.extend(useInPageId)
        for menu_ele in menu_obj:
            if menu_ele['id'] not in useInMenuId:
                continue
            if menu_ele["father_menu"] :
                sonId.append(menu_ele['id'])
                LayuiMenuDict[str(menu_ele["father_menu"])]["child"].append(LayuiMenuDict[str(menu_ele["id"])])
        for menu_ele in list(LayuiMenuDict.keys()):
            if not LayuiMenuDict[menu_ele].get("child"):
                del LayuiMenuDict[menu_ele]
            elif int(menu_ele) in sonId:
                del LayuiMenuDict[menu_ele]
        # 去掉id,做成列表加到默认的Menuinfo
        for item in LayuiMenuDict:
            self.LayuiLastMenu["menuInfo"].append(LayuiMenuDict[item])
        return self.LayuiLastMenu

在视图函数里面做一个生成菜单json的接口:

from tools.pemissionControl import *
import json
def print_json(data):
    print(json.dumps(data, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False))
def getMenu(request):
    user=request.session.get("username")
    per_obj=pemissionControl(user)
    Menu=per_obj.creatLayuiSimpleMenu()
    # Menu=per_obj.creatLayuiMenu()
    print_json(Menu)
    ret=HttpResponse(json.dumps(Menu))
    ret["X-Frame-Options"]="sameorigin"
    return ret

修改index.html中菜单获取页面的url:

把iniUrl的值换成视图getMenu

layui.use(['jquery', 'layer', 'miniAdmin','miniTongji'], function () {
        var $ = layui.jquery,
            layer = layui.layer,
            miniAdmin = layui.miniAdmin,
            miniTongji = layui.miniTongji;

        var options = {
            {#iniUrl: "/static/api/init.json",    // 初始化接口#}
            iniUrl: "/getMenu",    // 初始化接口
            clearUrl: "/static/api/clear.json", // 缓存清理接口
            urlHashLocation: true,      // 是否打开hash定位
            bgColorDefault: false,      // 主题默认配置
            multiModule: true,          // 是否开启多模块
            menuChildOpen: false,       // 是否默认展开菜单
            loadingTime: 0,             // 初始化加载时间
            pageAnim: true,             // iframe窗口动画
            maxTabNum: 20,              // 最大的tab打开数量
        };
        miniAdmin.render(options);

最终效果图:

debug:

1.TypeError:format() argument after ** must be a mapping,not list
  元组展开用*,字典展开用 **
  
2.字典添加字典
  dict1.update(dict2)
  
3.unhashable type: 'dict'
  原因:layui的目录是{}包裹起来的字典,也即{{}}
      但是python不支持这样,必须是键值对
  解决:先用{},再赋值完后再加{{}}
  后面发现不加也可以

后言:权限篇的绝大部分功能都已完备,唯一有个问题是因为是一次取出全部菜单,所以不同用户登录并没有隐藏菜单,而只隐藏了页面,若要隐藏菜单,只需修改InitMenuDict(self)函数即可

标签:菜单,layui,self,ele,item,menu,django,权限,id
来源: https://blog.51cto.com/linzb/2908665

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有