二、rbac組件 後臺佈局模板,權限按鈕,菜單,可拔插,路徑重定向

一、後臺佈局管理

https://www.cnblogs.com/venicid/p/7772742.html#_label0css

一、通用模板

 overflow: auto;       //在a和b模板中進行切換

a 模板 :左側菜單跟隨滾動條
 b模板  左側以及上不動 ****
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

<style type="text/css"> .header { width: 100%; height: 60px; background-color: #369; } .right { float: right; } .left { float: left; } .menu { position: absolute; top: 60px; left: 0; bottom: 0; background-color: gainsboro; width: 20%; } .content { position: absolute; top: 60px; right: 0; bottom: 0; background-color: mediumpurple; width: 80%; overflow: auto; //在a和b模板中進行切換 } </style> </head> <body> <div class="header"></div> <div class="container"> <div class="menu left"> 1111 </div> <div class="content right">222 {% block content %} {% endblock %} </div> </div> </body> </html>

 

二、模板繼承

users.html / roles.html 繼承自 base.html

users.htmlhtml

{% extends 'base.html' %}

{% block con %}
<h4>用戶列表</h4>
    {% for user in user_list %}
    <p>{{ user }}</p>
    {% endfor %}
    
{% endblock con%}

 

 二、權限按鈕控制:簡單控制

用戶權限不一樣,按鈕顯示就不一樣!

登陸成功後,就已經註冊了session
request.session['permission_list'] = permission_list

permission_list = request.session.get('permission_list')

    簡單控制:
        {% if "users/add" in permissions_list%} 

 

 

 

 三、修改表結構

BUT: 很差,不想讓 if "/users/add/" 寫死,會有 "/roles/add/" 狀況,不健壯!怎麼辦?      不該該根據表名,去判斷!! 
權限不一樣,按鈕顯示就不一樣 如何作呢?    
上面問題的解決辦法:
  爲了擴展,
  # 把兩條線 合成一個線
  /users/..
   /roles/...

一、admin顯示字段

注意:list_display = []

 

二、添加action,group字段

注意點:
加了一個權限組表,
將每張表的增刪改查,劃到一個組裏面!
不管多複雜的,最終必定是對數據庫的(增刪改查)

修改表結構,從新處理中間件,登陸頁面:
目的:全是爲了按鈕的粒度,同一個模板,同一個視圖,
顯示不一樣的數據,權限

 

from django.db import models


# Create your models here.

class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    roles = models.ManyToManyField(to='Role')

    def __str__(self):
        return self.name


class Role(models.Model):
    title = models.CharField(max_length=32)
    permissions = models.ManyToManyField(to="Permission")

    def __str__(self):
        return self.title


class Permission(models.Model):
    title = models.CharField(max_length=32)
    url = models.CharField(max_length=32)
    action = models.CharField(max_length=32, default="")

    group = models.ForeignKey(to="PermissionGroup", on_delete=True)
    def __str__(self):
        return self.title


class PermissionGroup(models.Model):
     title = models.CharField(max_length=32 )
     def __str__(self):
         return self.title
View Code

 

 

 

四、重構數據結構

一、登陸驗證

 

二、構建permission_dict

3.登陸以後,重寫 initial_session(user,request)
就是:
# 在session中註冊權限列表 用戶權限
# request.session['permission_list'] = permission_list

不該該是list 而是dict

# 在session中註冊權限字典
request.session['permission_dict'] = permission_dict

 注意點:git

permission = user.roles.all().values('permission__url', 'permission__group_id', 'permission__action').distinct()

  對數據的處理,以組爲鍵github

 
{1: {'urls': ['/users/', '/users/add/', '/users/delete/(\\d+)/', '/users/edit/(\\d+)/'], 
     'actions': ['list', 'add', 'delete', 'edit']}, 
 2: {'urls': ['/roles/'], 
     'actions': ['list']}}

 

# -*- coding: utf-8 -*-
# @Time    : 2018/08/11 0011 9:24
# @Author  : Venicid


def initial_session(request,user):
    # 方案2
    permissions = user.roles.all().values("permissions__url", "permissions__group_id","permissions__action").distinct()
    print(permissions)
    # <QuerySet [{'permissions__url': '/users/',
                # 'permissions__group_id': 1,
                # 'permissions__action': 'list'}]>

    permission_dict = {}
    for item in permissions:
        gid = item.get("permissions__group_id")
        if not gid in permission_dict:
            permission_dict[gid] = {
                "urls":[item["permissions__url"],],
                "actions":[item["permissions__action"],]
            }
        else:
            permission_dict[gid]["urls"].append(item["permissions__url"])
            permission_dict[gid]["actions"].append(item["permissions__action"])

    print(permission_dict)  # {1: {'urls': ['/users/'], 'actions': ['list']}}
    request.session["permission_dict"] = permission_dict


    # 方案1:
    """
    permissions = user.roles.all().values("permissions__url").distinct()

    permission_list = []
    for item in permissions:
        permission_list.append(item['permissions__url'])

    print(permission_list)  # ['/users/', '/users/add', '/users/delete/(\\d+)', '/users/edit/(\\d+)']

    request.session["permission_list"] = permission_list
    """

    """
    values :

    for role in user.roles.all():   # <QuerySet [<Role: 保潔>, <Role: 銷售>]>
        temp.append({
        "title":role.title,
        "permissions_url":role.permissions.all()
        })

    # <QuerySet [{'title': '保潔', 'permissions__url': '/users/'},
    # {'title': '銷售', 'permissions__url': '/users/'},
    # {'title': '銷售', 'permissions__url': '/users/add'}]>

    """
View Code

 

 

 

五、限制權限粒度

一、中間件校驗權限:

    # 注意:妙 !!
request.actions = item["actions"]

    

  

# -*- coding: utf-8 -*-
# @Time    : 2018/08/11 0011 9:04
# @Author  : Venicid

import re

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect


class ValidPermission(MiddlewareMixin):
    def process_request(self, request):

        # 當前訪問路徑
        current_path = request.path_info

        # 一、檢驗是否屬於白名單  白名單,不須要任何權限的url
        # 正則匹配
        valid_url_list = ['/login/', '/reg/', '/admin/.*']
        for valid_url in valid_url_list:
            ret = re.match(valid_url, current_path)

            if ret:
                return None

        # 二、校驗是否登陸
        user_id = request.session.get("user_id")
        if not user_id:
            return redirect('/login/')

        # 三、校驗權限2

        permission_dict = request.session.get("permission_dict", {})
        # {1: {'urls': ['/users/'], 'actions': ['list']}}

        for item in permission_dict.values():
            urls = item["urls"]
            for reg in urls:
                reg = "^%s$" % reg
                ret = re.match(reg, current_path)
                if ret:
                    print("actions",item["actions"])
                    request.actions = item["actions"]
                    return None
        return HttpResponse("沒有訪問權限")

        # 三、校驗權限1
        """
        permission_list = request.session.get("permission_list",[])
        print(permission_list)

        flag = False
        for permission in permission_list:
            permission = "^%s$" % permission
            # print(111111111,permission)
            # print(current_path)
            ret = re.match(permission, current_path)
            if ret:
                flag = True
                break

        if not flag:
            return HttpResponse("沒有訪問權限")
        return None
        """
rbac中間件

 

 

模板層,權限按鈕控制

2:用類來實現!!

from django.shortcuts import render, HttpResponse

# Create your views here.

from rbac.models import *
from rbac.service.perssions import *


class Per(object):
    def __init__(self, actions):
        self.actions = actions
    def add(self):
        return "add" in self.actions
    def delete(self):
        return "delete" in self.actions
    def edit(self):
        return "edit" in self.actions
    def list(self):
        return "list" in self.actions


def users(request):
    user_list = User.objects.all()
    permission_list = request.session.get("permission_list")

    # 查詢當前登陸人的名字
    id = request.session.get("user_id")
    user = User.objects.filter(id=id).first()
    print(user)

    per = Per(request.actions)

    return render(request, "users.html", locals())


def add_user(request):
    return HttpResponse('add user')


def delete_user(request, id):
    return HttpResponse('delete_user')


def edit_user(request, id):
    return HttpResponse('edit_user')


def roles(request):
    role_list = Role.objects.all()

    per = Per(request.actions)
    print(request.actions)
    return render(request, "roles.html", locals())


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        user = User.objects.filter(name=user, pwd=pwd).first()
        if user:
            ############## 在session中註冊用戶
            request.session['user_id'] = user.pk

            ############# 在session中註冊權限list
            initial_session(request, user)

            return HttpResponse("登陸成功")

    return render(request, 'login.html', locals())
View

 

 

三、效果

不一樣的用戶,具備不一樣的權限,ajax

權限不一樣,顯示的按鈕就不一樣!!數據庫

 

 六、權限不一樣,菜單顯示不一樣

只有查看,有必要放到菜單欄!
即:action == list 放到 菜單欄中

1.用戶登陸後,在initial_session中,註冊菜單權限

  注意:permission__group__title 還能夠這樣用,跨了3張表!!

# -*- coding: utf-8 -*-
# @Time    : 2018/08/11 0011 9:24
# @Author  : Venicid


def initial_session(request,user):
    # 方案2
    permissions = user.roles.all().values("permissions__url", "permissions__group_id","permissions__action").distinct()
    print(permissions)
    # <QuerySet [{'permissions__url': '/users/',
                # 'permissions__group_id': 1,
                # 'permissions__action': 'list'}]>

    permission_dict = {}
    for item in permissions:
        gid = item.get("permissions__group_id")
        if not gid in permission_dict:
            permission_dict[gid] = {
                "urls":[item["permissions__url"],],
                "actions":[item["permissions__action"],]
            }
        else:
            permission_dict[gid]["urls"].append(item["permissions__url"])
            permission_dict[gid]["actions"].append(item["permissions__action"])

    print(permission_dict)  # {1: {'urls': ['/users/'], 'actions': ['list']}}
    request.session["permission_dict"] = permission_dict


    # 註冊菜單權限
    permissions = user.roles.all().values("permissions__url", "permissions__action", "permissions__group__title").distinct()

    print(permissions)
    menu_permission_list = []
    for item in permissions:
        if item["permissions__action"] == "list":
            menu_permission_list.append((item["permissions__url"], item["permissions__group__title"]))

    print(menu_permission_list)   # [('/users/', '用戶組'), ('/roles/', '角色組')]
    request.session["menu_permission_list"] = menu_permission_list


    # 方案1:
    """
    permissions = user.roles.all().values("permissions__url").distinct()

    permission_list = []
    for item in permissions:
        permission_list.append(item['permissions__url'])

    print(permission_list)  # ['/users/', '/users/add', '/users/delete/(\\d+)', '/users/edit/(\\d+)']

    request.session["permission_list"] = permission_list
    """

    """
    values :

    for role in user.roles.all():   # <QuerySet [<Role: 保潔>, <Role: 銷售>]>
        temp.append({
        "title":role.title,
        "permissions_url":role.permissions.all()
        })

    # <QuerySet [{'title': '保潔', 'permissions__url': '/users/'},
    # {'title': '銷售', 'permissions__url': '/users/'},
    # {'title': '銷售', 'permissions__url': '/users/add'}]>

    """
View Code

 

 二、menu

 

能夠實現,菜單顯示!可是不行,爲何?

由於模板繼承,只繼承樣式,不繼承數據!全部須要用到 自定義標籤(inclusion_tag)

 

 三、自定義標籤(inclusion_tag)

 

# -*- coding: utf-8 -*-
# @Time    : 2018/08/12 0012 16:11
# @Author  : Venicid

from django import template

register = template.Library()


@register.inclusion_tag("rbac/menu.html")
def get_menu(request):
    # 獲取當前用戶能夠放到菜單欄中的權限
    menu_permission_list = request.session.get("menu_permission_list")

    print(menu_permission_list)

    return {"menu_permission_list":menu_permission_list}
View Code

 

+django

 

七、可拔插配置:包...建在哪一個App

    屬於權限的就建在rbac的APP裏,由於rpac最後是可插拔的組件!!

users.html / roles.html / base.html / menu.html
是和權限相關的,因此應該放在 rbac/templates/... 方便之後copy走!!

djangod的render去渲染 .html 時,先到項目的 templates 下找,找不到,再到App下 templates 下找,
最後找不到,才報錯!!

  

 

 若是多個App的templates 下的.html重名怎麼辦? django 會根據註冊的順序顯示!
解決辦法:
項目/rbac/templates/rbac/xxx.html

這時調用:
return render(request, 'rbac/users.html', locals())

注意:
templates 或者 templatetag 注意多個app下面 的文件名 有可能都會重名!!
辦法:就是 eg:/rbac/templates/rbac/xxx.html 或者不起重名

注意:
若是 base.html 在項目下有,在App下有,先找項目下的,找不到才找App
全局能夠覆蓋局部的!!

 

 

 八、路徑自動添加

知識點:路徑自動添加問題:
http://127.0.0.1:8010/users
http://127.0.0.1:8010/users/

瀏覽器發請求:
django 發現以後,發了一個重定向的 url 加了一個 /
全部才能匹配上:
path('users/', views.users),

如何讓django不給瀏覽器發重定向,不加 /
配置:
APPEND_SLASH = False

APPEND_SLASH = True # 默認爲 True

ajax 也是,django會默認的加 / 發重定向

一、django瀏覽器重定向

 

 二、APPEND_SLASH = False

  ajax 也是,django會默認的加 / 發重定向

 

 

 九、github代碼

https://github.com/venicid/rbac瀏覽器

相關文章
相關標籤/搜索