提及權限咱們你們都知道,不同的角色會有不同的權限。好比就像學生管理系統同樣,管理員,老師,學生之間的權限都是不同的,那麼展現的頁面也是不同的。因此,咱們如今來看看具體操做。html
目標:生成一個獨立的組件,到哪都能用python
一、先看配置文件合適不,給建立的rbac在配置文件裏面設置一下
找到INSTALLED_APPS=['rbac']數據庫
models中建立類:五個類,七張表
角色表:
用戶表:
權限表:django
權限組表:session
菜單表: app
角色表和權限表是多對多的關係(一個角色能夠有多個權限,一個權限能夠對應多個角色)
用戶表和角色表是多對多的關係(一個用戶能夠有多個角色,一個角色有多個用戶)函數
因此有會多生成兩張關係表url
一個菜單下面有多個組spa
一個組下面有多個菜單設計
一個菜單下面有多個權限
from django.db import models # Create your models here. class Role(models.Model): title = models.CharField(max_length=32,verbose_name="角色") permissions = models.ManyToManyField(to="Permission",verbose_name="擁有權限的角色",blank=True) #權限和角色是多對多的關係 def __str__(self): return self.title class Meta: verbose_name_plural = "角色表" class Permission(models.Model): title = models.CharField(max_length=32,verbose_name="權限名") url = models.CharField(max_length=32,verbose_name="帶正則的url") codes = models.CharField(max_length=32,verbose_name="代碼") group = models.ForeignKey(to="Group",verbose_name="所屬組",blank=True) #組和權限是一對多的關係,一個組有多個權限 menu_gp = models.ForeignKey(to='Permission',related_name='aaa',null=True,blank=True,verbose_name="組內菜單") def __str__(self): return self.title class Meta: verbose_name_plural = "權限表" class UserInfo(models.Model): name = models.CharField(max_length=32,verbose_name="姓名") password = models.CharField(max_length=64,verbose_name="密碼") email = models.CharField(max_length=32,verbose_name="郵箱") roles = models.ManyToManyField(to="Role",blank=True) #用戶和角色是多對多的關係 def __str__(self): return self.name class Meta: verbose_name_plural = "用戶表" class Group(models.Model): title = models.CharField(max_length=32,verbose_name="組名稱") menu = models.ForeignKey(to="Menu",verbose_name="組內菜單",blank=True) #一個組下有多個菜單 def __str__(self): return self.title class Meta: verbose_name_plural = "權限組" class Menu(models.Model): caption = models.CharField(max_length=32,verbose_name="菜單") def __str__(self): return self.caption class Meta: verbose_name_plural = "菜單表"
一、咱們通常是先看到的是列表頁面,在這個頁面上是否顯示添加,是否顯示編輯,是否顯示刪除,都是須要判斷的
有無添加權限,有無刪除權限,有無編輯權限,咱們能夠給每個url一個代號
dict = { 1:{ 代號 /userinfo/ list /userinfo/add/ add /userinfo/del(\d+)/ del /userinfo/edit(\d+)/ edit } }
不只在列表頁面須要知道他有那些權限,在其餘頁面也知道他有那些權限
因此上面的方案仍是有點很差,那麼咱們採起下面的方案。將代號取出來放在一個列表裏面
dict = { 1:{ "codes":["list","add","del","edit"] urls:[ "/userinfo/", "/userinfo/add"/, "/userinfo/del(\d+)/ ", "/userinfo/edit(\d+)/ ", ] } 2:{ "codes":{"list","add","del","edit"} urls:[ "/order", "/order/add"/, "/order/del(\d+)/ ", "/order/edit(\d+)/ ", ] } }
把這個字典存到session中當你訪問頁面的時候我就知道你有什麼權限一個url對應一個code 多個url對應一個組
注意:
關聯字段 null = True 數據庫用的時候能夠爲空
關聯字段 blank = True admin用的時候能夠爲空
當出現這個錯誤的時候
python manage.py migrate --fake 廢棄
- 先建立一個超級用戶 python3 manage.py createsuperuser - 用戶名 root - 密碼 zhy123456 - 在admin.py 中 from rbac import models admin.site.register(models.Permission) admin.site.register(models.Role) admin.site.register(models.UserInfo) 這樣的話上去的是英文的,若是你想讓中文顯示就在類中加一個類 class Meta: verbose_name_plural = "權限表" - 當你給關聯字段錄入數據的時候會有錯誤提示,那麼在類中你的那個關聯字段在加一個屬性blank = True 能夠爲空 permissions = models.ManyToManyField(to="Permission",verbose_name="具備的全部權限", blank=True)
1.編寫登陸
2.若是用戶驗證成功就設置session
3.先查出當前用戶的全部的權限
4.從這些權限中找到全部的url,吧這些url放到session中
這些都是在rbac裏面的操做,若是咱們作一些複雜的操做,可能會有好多的代碼
咱們寫rbac的目的是作成一個公共的組件,爲了讓別人省事
咱們在建立一個server的文件夾,裏面建立一個init_permission的py文件。
dict = { 1:{ "codes":["list","add","del","edit"] urls:[ "/userinfo/", "/userinfo/add"/, "/userinfo/del(\d+)/ ", "/userinfo/edit(\d+)/ ", ] } 2:{ "codes":{"list","add","del","edit"} urls:[ "/order", "/order/add"/, "/order/del(\d+)/ ", "/order/edit(\d+)/ ", ] } }
5.拿到用戶請求的url去session裏面作驗證
獲取當前請求的url
獲取session中保存當前用戶的權限
而後開始驗證
若是匹配成功就有權訪問
若是匹配不成功就無權訪問
用re去匹配的時候,re.match(/userinfo/,/userinfo/add) #都能匹配到
那麼要記得在匹配正則的時候加個起始符和終止符regex = "^{0}$".format(url)
def login(request):
.....
設置session
def index(request):
....
獲取session
def userinfo(request):
獲取session
這樣若是有好多個函數,就的重複好多代碼,咱們能夠用中間件來處理
中間件和裝飾器的區別:
中間件用來作批量處理
若是函數很少的話能夠用加裝飾器的方法
class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response
views
def userinfo(request): # 方式一 # Page_permission = request.permission_code_list # 方式二:實例化 page_permission = BasePagePermission(request.permission_code_list) print("page_permission",request.permission_code_list) data_list = [ {"id":1,"name":"xxx1"}, {"id":2,"name":"xxx2"}, {"id":3,"name":"xxx3"}, {"id":4,"name":"xxx4"}, {"id":5,"name":"xxx5"}, ] return render(request,"userinfo.html",{"data_list":data_list,"page_permission":page_permission})
方式一:
<table> {% if "add" in Page_permission %} <a href="#">添加</a> {% endif %} {% for row in data_list %} <tr> <td>{{ row.id }}</td> <td>{{ row.name }}</td> {% if "edit" in Page_permission %} <td><a href="#">編輯</a></td> {% endif %} {% if "del" in Page_permission %} <td>{<a href="#">刪除</a></td> {% endif %} </tr> {% endfor %} </table>
方式二:
吧permission_code_list處理一下 在views中定義一個類 class BasePagePermission(object): def __init__(self,code_list): self.code_list = code_list def has_add(self): if "add" in self.code_list: return True def has_del(self): if "del" in self.code_list: return True def has_edit(self): if "edit" in self.code_list: return True 實例化:page_permission = BasePagePermission(request.permission_code_list) 在模板中 <table> {% if page_permission.has_add %} <a href="#">添加</a> {% endif %} {% for row in data_list %} <tr> <td>{{ row.id }}</td> <td>{{ row.name }}</td> {% if page_permission.has_edit %} <td><a href="#">編輯</a></td> {% endif %} {% if page_permission.has_del %} <td>{<a href="#">刪除</a></td> {% endif %} </tr> {% endfor %} </table>
一、如何生成菜單
二、怎麼讓這些菜單分級顯示而且若是當前訪問的url權限默認展開若是是組內菜單就加粗或者變紅
三、非菜單url,默認選中原菜單。(若是你是點擊用戶列表進來的,那麼你看到頁面了,若是你點擊添加的時候,你的那個用戶列看不見了,這就很差了。因此要設計當你點擊添加按鈕的時候,那個用戶列表被默認選中)
菜單管理
菜單一
用戶管理
權限管理
菜單二
訂單管理
角色管理
分級作了菜單。這些菜單該顯示什麼菜單?是當前用戶登陸以後從數據庫拿到這個用戶擁有的權限,而後把權限搞成菜單
在表裏面設計了一個組內菜單(自關聯 ),當menu_gp_id爲NULL就表明能夠做爲菜單
menu_list = [] for item in permission_list: tpl = { "id":item["permissions__id"], "title":item["permissions__title"], "url":item["permissions__url"], "menu_gp_id":item["permissions__menu_gp_id"], "menu_id":item["permissions__group__menu_id"], "menu_title":item["permissions__group__menu__caption"] } menu_list.append(tpl) request.session[settings.PERMISSION_MENU_KEY] = menu_list
重要:
由於是要在頁面上渲染,通常咱們會在視圖函數的render裏面加{"":變量}這樣渲染,
可是還有個更好用的方法:用自定義的標籤
具體操做:
一、找到app建立一個templatetags的文件夾
二、而後在裏面隨便建立一個文件
三、導入form django.template import Library
register = Library()
方式一:
@register.simple_tag
def menu():
return "菜單" 這裏返回啥頁面上就顯示啥
而後在母版裏面導入mnue.html
{% load rbac %}
方式二:
@register.includsion_tag("xxx.html") #這裏存放的是html文件,,,@register.includsion_tag("xxx.html") 自動會讀這個文件而且把返回值拿到在頁面上渲染
def menu():
return "菜單" 這裏返回啥頁面上就顯示啥
「在母版中:{%menu_html request%} request是參數,記得要加上{% load rbac %}
四、注意:
若是有兩個文件夾同名,避免發生衝突:就再建立一個文件夾包起來
menu_list = [ {'id': 1, 'title': '用戶列表', 'url': '/userinfo/', 'menu_gp_id': None, 'menu_id': 2, 'menu_title': '菜單二'}, {'id': 2, 'title': '添加用戶', 'url': '/userinfo/add/', 'menu_gp_id': 1, 'menu_id': 2, 'menu_title': '菜單二'}, {'id': 3, 'title': '刪除用戶', 'url': '/userinfo/del/(\\d+)/', 'menu_gp_id': 1, 'menu_id': 2, 'menu_title': '菜單二'}, {'id': 4, 'title': '編輯用戶', 'url': '/userinfo/edit/(\\d+)/', 'menu_gp_id': 1, 'menu_id': 2, 'menu_title': '菜單二'}, {'id': 5, 'title': '訂單列表','url': '/order/', 'menu_gp_id': None, 'menu_id': 1, 'menu_title': '菜單一'}, {'id': 6, 'title': '添加訂單', 'url': '/order/add/', 'menu_gp_id': 2, 'menu_id': 1, 'menu_title': '菜單一'}, {'id': 7, 'title': '刪除訂單', 'url': '/order/del/(\\d+)/', 'menu_gp_id': 2, 'menu_id': 1, 'menu_title': '菜單一'}, {'id': 8, 'title': '編輯訂單', 'url': '/order/edit/(\\d+)/', 'menu_gp_id': 2, 'menu_id': 1, 'menu_title': '菜單一'} ]
{ 1: {'id': 1, 'title': '用戶列表', 'url': '/userinfo/', 'menu_gp_id': None, 'menu_id': 2, 'menu_title': '菜單二'}, 5: {'id': 5, 'title': '訂單列表', 'url': '/order/', 'menu_gp_id': None, 'menu_id': 1, 'menu_title': '菜單一'} }
{ 1: {'id': 1, 'title': '用戶列表', 'url': '/userinfo/', 'menu_gp_id': None, 'menu_id': 2, 'menu_title': '菜單二', 'active': True}, 5: {'id': 5, 'title': '訂單列表', 'url': '/order/', 'menu_gp_id': None, 'menu_id': 1, 'menu_title': '菜單一'} }
{ 1: { 'menu_id': 1, 'menu_title': '菜單一', 'active': None, 'children': [ {'title': '訂單列表', 'url': '/order/', 'active': None} ] } 2: { 'menu_id': 2, 'menu_title': '菜單二', 'active': True, 'children': [ {'title': '用戶列表', 'url': '/userinfo/', 'active': True} ] }, }