昨天的做業,有不少不完善的地方css
下載代碼,基本實現權限驗證html
https://github.com/987334176/luffy_permission/archive/v1.2.zip前端
必須下載此代碼,不然下面的不用看了!!!python
補充說明:jquery
查看rbac目錄下的admin.py,看下面幾行代碼git
class PermissionAdmin(admin.ModelAdmin): list_display = ['title','url'] # 顯示的字段 list_editable = ['url'] # 容許編輯 admin.site.register(models.Permission,PermissionAdmin)
它能實現下面的效果:github
url能夠直接編輯。注意url的最前面,必須包含"/",爲何呢?後面作菜單的時候,會用到!web
查看web目錄-->views目錄下的account.py,看這一行數據庫
permission_list = obj.roles.filter(permissions__url__isnull=False).values('permissions__url').distinct()
有些用戶,是沒有角色的。須要使用permissions__url__isnull=False 過濾掉爲空的記錄apache
因爲權限判斷,只須要url。因此取url字段,也就是 values('permissions__url')
因爲用戶可能有多個角色,那麼url必然有重複的。使用 distinct() 作去重!
在django中session存儲時,默認對數據作序列化。因此數據不能是queryset對象,使用list進行強制轉換!
權限在不少地方會用到,爲了不key放生變更,致使處處代碼改動。將key名放在settings.py中。
新建一個11.py文件,內容以下:
current_url = '/customer/edit/1/' reg = "^/customer/edit/(\d+)/$" import re result = re.match(reg,current_url) print(result)
執行輸出:
<_sre.SRE_Match object; span=(0, 17), match='/customer/edit/1/'>
輸入一個不匹配的
current_url = '/customer/edit/1/dfasfsda' reg = "^/customer/edit/(\d+)/$" import re result = re.match(reg,current_url) print(result)
執行輸出:None
注意:這裏必須使用match,它表示從頭至尾匹配。不能使用search和findall
search表示有多個結果時,只輸出第一個!
查看web目錄-->middleware目錄-->rbac.py,看這一行代碼
reg = "^%s$" % item.get('permissions__url')
它表示爲每個url增長開始符號"^"和結束符號"$"
這樣,就能精確匹配了!
對於白名單,也就是不須要進行權限驗證的。寫在settings.py中,方便擴展!
上述過程當中的菜單是在程序中定義好的,沒法根據用戶權限進行動態配置。
那麼,接下來咱們來完成一個 「單級菜單」的功能:
看下面的url,有些能夠成爲菜單,有些不能!
上面紅色方框的,就是菜單。其餘的,好比帶參數的。它是動態連接,所以不能成爲菜單!
那麼如何區分呢?給權限表加2個字段,一個表示是否可作菜單,一個是菜單的圖標。
進入目錄rbac,修改models.py
from django.db import models class Permission(models.Model): """ 權限表 """ title = models.CharField(verbose_name='標題', max_length=32) url = models.CharField(verbose_name='含正則的URL', max_length=128) is_menu = models.BooleanField(verbose_name='是否可作菜單', default=False) icon = models.CharField(verbose_name='菜單圖標',max_length=32, null=True, blank=True) 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
執行2個命令,生成字段
python manage.py makemigrations
python manage.py migrate
一套絕佳的圖標字體庫和CSS框架,Font Awesome爲您提供可縮放的矢量圖標,您可使用CSS所提供的全部特性對它們進行更改,包括:大小、顏色、陰影或者其它任何支持的效果。
官方網址:
http://fontawesome.dashgame.com/
將如下代碼粘貼到網頁HTML代碼的 <head> 部分
<link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
您能夠將Font Awesome圖標使用在幾乎任何地方,只須要使用CSS前綴 fa
,再加上圖標名稱。 Font Awesome是爲使用內聯元素而設計的。咱們一般更喜歡使用 <i>
,由於它更簡潔。 但實際上使用 <span>
才能更加語義化。
<i class="fa fa-camera-retro"></i> fa-camera-retro
官方沒有提供圖標搜索功能,這裏提供一個網站,能夠搜索你想要的圖標
https://www.thinkcmf.com/font/search.html
還有一個
修改web目錄-->views-->account.py
from django.shortcuts import render, redirect, HttpResponse from rbac import models from django.conf import settings def login(request): """ 用戶登錄 :param request: :return: """ if request.method == 'GET': return render(request, 'login.html') # 1. 獲取提交的用戶名和密碼 user = request.POST.get('user') pwd = request.POST.get('pwd') # 2. 檢驗用戶是否合法 obj = models.UserInfo.objects.filter(name=user, password=pwd).first() if not obj: return render(request, 'login.html', {'msg': '用戶名或密碼錯誤'}) # 3. 獲取用戶信息和權限信息寫入session permission_queryset = obj.roles.filter(permissions__url__isnull=False).values('permissions__url', 'permissions__is_menu', 'permissions__title', 'permissions__icon', ).distinct() menu_list = [] # 菜單列表 permission_list = [] # 權限列表 for row in permission_queryset: permission_list.append({'permissions__url': row['permissions__url']}) if row['permissions__is_menu']: menu_list.append( {'title': row['permissions__title'], 'icon': row['permissions__icon'], 'url': row['permissions__url']}) request.session[settings.PERMISSION_SESSION_KEY] = permission_list request.session[settings.MENU_SESSION_KEY] = menu_list return redirect('/customer/list/')
修改settings.py,增長變量
########################## 權限相關 ####################### PERMISSION_SESSION_KEY = "permission_list" MENU_SESSION_KEY = "menu_list" VALID_URL = [ '^/login/$', '^/admin/.*', ]
經過這樣,權限和菜單,就分開了。各不影響!
菜單在是web目錄-->templates目錄-->layout.html裏面的
對於每一個用戶展現不一樣的菜單,須要分離出來。須要使用自定義標籤來渲染!
在web目錄下面建立templatetags文件夾,在此文件夾中建立rbac.py
from django.template import Library from django.conf import settings import re register = Library() @register.inclusion_tag('menu.html') def menu(request): """ 生成菜單 :param request: :return: """ # 獲取session中的菜單列表 menu_list = request.session.get(settings.MENU_SESSION_KEY) for item in menu_list: # 每個url增長^$,好比/customer/list/變成^/customer/list/$ reg = "^%s$" % item['url'] if re.match(reg,request.path_info): # 判斷當前路徑是否匹配 # 增長一個樣式,class爲action。表示選中狀態 item['class'] = 'active' return {'menu_list':menu_list} # 變量傳給模板
在web目錄-->templates目錄下,建立menu.html
<div class="static-menu"> {% for item in menu_list %} <a href="{{ item.url }}" class="{{ item.class }}"> <span class="icon-wrap"><i class="fa {{ item.icon }}"></i></span> {{ item.title }}</a> {% endfor %} </div>
修改web目錄-->templates目錄-->layout.html,使用自定義標籤
{% load staticfiles %} {% load rbac %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>路飛學城</title> <link rel="shortcut icon" href="{% static 'imgs/luffy-study-logo.png' %} "> <link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.css' %} "/> <link rel="stylesheet" href="{% static 'plugins/font-awesome/css/font-awesome.css' %} "/> <link rel="stylesheet" href="{% static 'css/commons.css' %} "/> <link rel="stylesheet" href="{% static 'css/nav.css' %} "/> <style> body { margin: 0; } .no-radius { border-radius: 0; } .no-margin { margin: 0; } .pg-body > .left-menu { background-color: #EAEDF1; position: absolute; left: 1px; top: 48px; bottom: 0; width: 220px; border: 1px solid #EAEDF1; overflow: auto; } .pg-body > .right-body { position: absolute; left: 225px; right: 0; top: 48px; bottom: 0; overflow: scroll; border: 1px solid #ddd; border-top: 0; font-size: 13px; min-width: 755px; } .navbar-right { float: right !important; margin-right: -15px; } .luffy-container { padding: 15px; } .left-menu .menu-body .static-menu { } .left-menu .menu-body .static-menu .icon-wrap { width: 20px; display: inline-block; text-align: center; } .left-menu .menu-body .static-menu a { text-decoration: none; padding: 8px 15px; border-bottom: 1px solid #ccc; color: #333; display: block; background: #efefef; background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa)); background: -ms-linear-gradient(bottom, #efefef, #fafafa); background: -moz-linear-gradient(center bottom, #efefef 0%, #fafafa 100%); background: -o-linear-gradient(bottom, #efefef, #fafafa); filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')"; box-shadow: inset 0px 1px 1px white; } .left-menu .menu-body .static-menu a:hover { color: #2F72AB; border-left: 2px solid #2F72AB; } .left-menu .menu-body .static-menu a.active { color: #2F72AB; border-left: 2px solid #2F72AB; } </style> </head> <body> <div class="pg-header"> <div class="nav"> <div class="logo-area left"> <a href="#"> <img class="logo" src="{% static 'imgs/logo.svg' %}"> <span style="font-size: 18px;">路飛學城 </span> </a> </div> <div class="left-menu left"> <a class="menu-item">資產管理</a> <a class="menu-item">用戶信息</a> <a class="menu-item">路飛管理</a> <div class="menu-item"> <span>使用說明</span> <i class="fa fa-caret-down" aria-hidden="true"></i> <div class="more-info"> <a href="#" class="more-item">管他什麼菜單</a> <a href="#" class="more-item">實在是編不了</a> </div> </div> </div> <div class="right-menu right clearfix"> <div class="user-info right"> <a href="#" class="avatar"> <img class="img-circle" src="{% static 'imgs/default.png' %}"> </a> <div class="more-info"> <a href="#" class="more-item">我的信息</a> <a href="#" class="more-item">註銷</a> </div> </div> <a class="user-menu right"> 消息 <i class="fa fa-commenting-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 通知 <i class="fa fa-envelope-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 任務 <i class="fa fa-bell-o" aria-hidden="true"></i> <span class="badge bg-danger">4</span> </a> </div> </div> </div> <div class="pg-body"> <div class="left-menu"> <div class="menu-body"> {% menu request %} </div> </div> <div class="right-body"> <div> <ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;"> <li><a href="#">首頁</a></li> <li class="active">客戶管理</li> </ol> </div> {% block content %} {% endblock %} </div> </div> <script src="{% static 'js/jquery-3.3.1.min.js' %} "></script> <script src="{% static 'plugins/bootstrap/js/bootstrap.js' %} "></script> {% block js %} {% endblock %} </body> </html>
使用徹底權限的用戶,登陸頁面,效果以下:
使用非徹底權限的用戶登陸
效果以下:
經過這樣,就能夠不一樣的用戶登陸,動態的展現菜單!
那麼問題來了,在web應用中。設計到權限的,都在此目錄中。這樣是不合理的,得須要把相關代碼移植到rbac應用中!
將web目錄下的middleware文件夾,剪貼到rbac目錄中
修改settings.py,修改中間件的路徑
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'rbac.middleware.rbac.RbacMiddleware', ]
在rbac目錄下,建立文件夾service,在此路徑下建立文件init_permission.py,表示權限初始化
from django.conf import settings def init_permission(request,user): """ 權限和菜單信息初始化,之後使用時,須要在登錄成功後調用該方法將權限和菜單信息放入session :param request: :param user: :return: """ # 3. 獲取用戶信息和權限信息寫入session permission_queryset = user.roles.filter(permissions__url__isnull=False).values('permissions__url', 'permissions__is_menu', 'permissions__title', 'permissions__icon', ).distinct() menu_list = [] permission_list = [] for row in permission_queryset: permission_list.append({'permissions__url': row['permissions__url']}) if row['permissions__is_menu']: menu_list.append( {'title': row['permissions__title'], 'icon': row['permissions__icon'], 'url': row['permissions__url']}) request.session[settings.PERMISSION_SESSION_KEY] = permission_list request.session[settings.MENU_SESSION_KEY] = menu_list
修改web目錄-->views目錄-->account.py
from django.shortcuts import render, redirect, HttpResponse from rbac import models from rbac.service.init_permission import init_permission from django.conf import settings def login(request): """ 用戶登錄 :param request: :return: """ if request.method == 'GET': return render(request, 'login.html') # 1. 獲取提交的用戶名和密碼 user = request.POST.get('user') pwd = request.POST.get('pwd') # 2. 檢驗用戶是否合法 obj = models.UserInfo.objects.filter(name=user, password=pwd).first() if not obj: return render(request, 'login.html', {'msg': '用戶名或密碼錯誤'}) # 寫入session request.session['user_info'] = {'id': obj.id, 'name': obj.name} # 初始化權限,並寫入session init_permission(request, obj) return redirect('/customer/list/')
在rbac目錄-->建立templates-->建立rbac文件夾,避免文件衝突。將web目錄-->templates裏面的menu.html剪切過來
將web目錄下的templatetags文件夾剪貼到rbac目錄下
修改rbac目錄-->templatetags-->rbac.py,更改模板路徑
from django.template import Library from django.conf import settings import re register = Library() @register.inclusion_tag('rbac/menu.html') def menu(request): """ 生成菜單 :param request: :return: """ # 獲取session中的菜單列表 menu_list = request.session.get(settings.MENU_SESSION_KEY) for item in menu_list: # 每個url增長^$,好比/customer/list/變成^/customer/list/$ reg = "^%s$" % item['url'] if re.match(reg,request.path_info): # 判斷當前路徑是否匹配 # 增長一個樣式,class爲action。表示選中狀態 item['class'] = 'active' return {'menu_list':menu_list} # 變量傳給模板
在rbac目錄-->建立目錄static-->建立目錄rbac,在此文件下建立文件rbac.css
.static-menu { } .static-menu .icon-wrap { width: 20px; display: inline-block; text-align: center; } .static-menu a { text-decoration: none; padding: 8px 15px; border-bottom: 1px solid #ccc; color: #333; display: block; background: #efefef; background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa)); background: -ms-linear-gradient(bottom, #efefef, #fafafa); background: -moz-linear-gradient(center bottom, #efefef 0%, #fafafa 100%); background: -o-linear-gradient(bottom, #efefef, #fafafa); filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')"; box-shadow: inset 0px 1px 1px white; } .static-menu a:hover { color: #2F72AB; border-left: 2px solid #2F72AB; } .static-menu a.active { color: #2F72AB; border-left: 2px solid #2F72AB; }
修改web目錄-->templates-->layout.html。刪除多餘的css文件
{% load staticfiles %} {% load rbac %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>路飛學城</title> <link rel="shortcut icon" href="{% static 'imgs/luffy-study-logo.png' %} "> <link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.css' %} "/> <link rel="stylesheet" href="{% static 'plugins/font-awesome/css/font-awesome.css' %} "/> <link rel="stylesheet" href="{% static 'css/commons.css' %} "/> <link rel="stylesheet" href="{% static 'css/nav.css' %} "/> <link rel="stylesheet" href="{% static 'rbac/rbac.css' %} "/> <style> body { margin: 0; } .no-radius { border-radius: 0; } .no-margin { margin: 0; } .pg-body > .left-menu { background-color: #EAEDF1; position: absolute; left: 1px; top: 48px; bottom: 0; width: 220px; border: 1px solid #EAEDF1; overflow: auto; } .pg-body > .right-body { position: absolute; left: 225px; right: 0; top: 48px; bottom: 0; overflow: scroll; border: 1px solid #ddd; border-top: 0; font-size: 13px; min-width: 755px; } .navbar-right { float: right !important; margin-right: -15px; } .luffy-container { padding: 15px; } </style> </head> <body> <div class="pg-header"> <div class="nav"> <div class="logo-area left"> <a href="#"> <img class="logo" src="{% static 'imgs/logo.svg' %}"> <span style="font-size: 18px;">路飛學城 </span> </a> </div> <div class="left-menu left"> <a class="menu-item">資產管理</a> <a class="menu-item">用戶信息</a> <a class="menu-item">路飛管理</a> <div class="menu-item"> <span>使用說明</span> <i class="fa fa-caret-down" aria-hidden="true"></i> <div class="more-info"> <a href="#" class="more-item">管他什麼菜單</a> <a href="#" class="more-item">實在是編不了</a> </div> </div> </div> <div class="right-menu right clearfix"> <div class="user-info right"> <a href="#" class="avatar"> <img class="img-circle" src="{% static 'imgs/default.png' %}"> </a> <div class="more-info"> <a href="#" class="more-item">我的信息</a> <a href="#" class="more-item">註銷</a> </div> </div> <a class="user-menu right"> 消息 <i class="fa fa-commenting-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 通知 <i class="fa fa-envelope-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 任務 <i class="fa fa-bell-o" aria-hidden="true"></i> <span class="badge bg-danger">4</span> </a> </div> </div> </div> <div class="pg-body"> <div class="left-menu"> <div class="menu-body"> {% menu request %} </div> </div> <div class="right-body"> <div> <ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;"> <li><a href="#">首頁</a></li> <li class="active">客戶管理</li> </ol> </div> {% block content %} {% endblock %} </div> </div> <script src="{% static 'js/jquery-3.3.1.min.js' %} "></script> <script src="{% static 'plugins/bootstrap/js/bootstrap.js' %} "></script> {% block js %} {% endblock %} </body> </html>
重啓django項目,從新登陸,效果同上!
rbac組件就獨立出來了,之後想用的話,複製整個文件夾。
並作一些相關配置,就可使用了!
完整代碼,請訪問github
https://github.com/987334176/luffy_permission/archive/v1.4.zip
新建一個項目untitled,注意django 版本爲1.11
修改models.py,增長2個表
from django.db import models class Classes(models.Model): name = models.CharField(max_length=32) class Student(models.Model): name = models.CharField(max_length=32)
修改urls.py,增長路徑
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/$', views.login), url(r'^student/$', views.student), url(r'^student/add/$', views.student_add), ]
修改views.py,增長視圖函數
from django.shortcuts import render # Create your views here. def login(request): """ 用戶登錄 :param request: :return: """ if request.method == 'GET': return render(request,'login.html') def student(request): return render(request,'student.html') def student_add(request): return render(request, 'student_add.html')
在templates新增文件layout.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div style="height: 48px;background-color: aquamarine"></div> <div> <div style="width: 20%;float: left;background-color: #dddddd"> 菜單 </div> <div style="width: 80%;float: left"> {% block content %} {% endblock %} </div> </div> </body> </html>
student_add.html
{% extends 'layout.html' %} {% block content %} <h1>添加學生</h1> {% endblock %}
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="post"> {% csrf_token %} <input type="text" name="user"> <input type="password" name="pwd"> <input type="submit" value="提交"> {{ msg }} </form> </body> </html>
student.html
{% extends 'layout.html' %} {% block content %} <h1>學生列表</h1> {% endblock %}
啓動djang項目,訪問頁面
http://127.0.0.1:8000/student/add/
效果以下:
將上面的rbac文件中,直接copy到項目根目錄
進入rbac目錄中的migrations文件夾,將裏面的全部文件刪除
修改settings.py,註冊rbac到app
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 'rbac.apps.RbacConfig', ]
使用2個命令,生成表。注意:定義要帶上應用名rbac,不然沒法生成表!
python manage.py makemigrations rbac
python manage.py migrate
查看錶是否生成了
建立超級用戶
python manage.py createsuperuser
查看admin.py
from django.contrib import admin from rbac import models class PermissionAdmin(admin.ModelAdmin): list_display = ['title','url'] # 顯示的字段 list_editable = ['url'] # 容許編輯 admin.site.register(models.Permission,PermissionAdmin) admin.site.register(models.Role) admin.site.register(models.UserInfo)
登陸後臺,添加數據
添加角色
添加用戶
修改app01目錄下的views.py
from django.shortcuts import render, redirect,HttpResponse from rbac import models from rbac.service.init_permission import init_permission def login(request): """ 用戶登錄 :param request: :return: """ if request.method == 'GET': return render(request,'login.html') # 1. 獲取提交的用戶名和密碼 user = request.POST.get('user') pwd = request.POST.get('pwd') # 2. 檢驗用戶是否合法 obj = models.UserInfo.objects.filter(name=user,password=pwd).first() if not obj: return render(request, 'login.html',{'msg':'用戶名或密碼錯誤'}) request.session['user_info'] = {'id': obj.id, 'name': obj.name} init_permission(request,obj) return redirect('/student/') def student(request): return render(request,'student.html') def student_add(request): return render(request, 'student_add.html')
修改settings.py,註冊中間件
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'rbac.middleware.rbac.RbacMiddleware', ]
修改settings.py,最後一行添加
########################## 權限相關 ####################### PERMISSION_SESSION_KEY = "permission_list" MENU_SESSION_KEY = "menu_list" VALID_URL = [ '^/login/$', '^/admin/.*', ]
{% load staticfiles %} <link rel="stylesheet" href="{% static 'rbac/rbac.css' %}" />
{% load rbac %}
{% menu request %}
修改app01-->templates-->layout.html
{% load staticfiles %} {% load rbac %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> <link rel="stylesheet" href="{% static 'rbac/rbac.css' %}" /> {% block css %} {% endblock %} </head> <body> <div style="height: 48px;background-color: aquamarine"></div> <div> <div style="width: 20%;float: left;background-color: #dddddd"> {% menu request %} </div> <div style="width: 80%;float: left"> {% block content %} {% endblock %} </div> </div> {% block js %} {% endblock %} </body> </html>
登陸帳戶
查看頁面
總結:
如何在其餘系統中應用目前的rbac組件。 a. 拷貝rbac組件 b. 清空migrations目錄 c. 註冊rbac 到app d. 數據庫遷移並錄入權限信息 e. 用戶登錄作權限和菜單的初始化 init_permission f. 應用中間件進行權限校驗 g. 設置配置文件 ########################## 權限相關 ####################### PERMISSION_SESSION_KEY = "permission_list" MENU_SESSION_KEY = "menu_list" VALID_URL = [ '^/login/$', '^/admin/.*', ] h. 顯示動態菜單 - 引入css {% load staticfiles %} <link rel="stylesheet" href="{% static 'rbac/rbac.css' %}" /> - 調用動態菜單 {% load rbac %} {% menu request %} 合起來: {% load staticfiles %} {% load rbac %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{% static 'rbac/rbac.css' %}" /> {% block css %} {% endblock %} </head> <body> <div style="height: 48px;background-color: aquamarine"></div> <div> <div style="width: 20%;float: left;background-color: #dddddd"> {% menu request %} </div> <div style="width: 80%;float: left"> {% block content %} {% endblock %} </div> </div> {% block js %} {% endblock %} </body> </html>
在django project中建立 static文件夾
settings.py中配置要在 STATIC_URL = '/static/' 下邊
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
或
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
在頁面的較上處寫:
{% load staticfiles %}
在 link script 等src 寫 :
{%static 'xxx.css'%} {%static 'xxx.js'%}
完整代碼:
<link rel="stylesheet" href="{%static 'xxx.css'%} "/> <script src="{%static 'xxx.js'%} "></script>
在 link script 等src 寫
/static/xxx.cs
二者可混用,但不推薦!
推薦使用方式一
默認的django程序,會設置STATIC_URL
Django 默認會在各app下的static文件夾中找文件。注意有前後順序,找到了就再也不繼續找了!、
那在模版中使用這些靜態文件時,使用
{%static 'sample.css'%} {%static 'xxx.js'%}
Django在運行時會自動將這些文件映射到STATIC_URL所給定的值下。也就是如,若是STATIC_URL = '/static/',那麼在運行時,上邊模版中的樣例中的url會被替換爲/static/css/sample.css
1.其實將靜態文件路徑硬編碼在模版中也能夠正常運行,如使用href="/static/css/sample.css",前提是配置好了STATIC_URL和STATIC_DIRS。但並不推薦這麼作,由於若是後來靜態資源的位置發生了遷移,如使用獨立服務器或者使用CDN,就要修改一大堆URL。而使用推薦的方法能夠避免這個龐大的工做量,最多隻須要修改STATIC_URL便可。
2.若是css文件中也使用了靜態文件如css背景,則按照相對路徑使用便可,由於瀏覽器解析css是會自動按照相對路徑尋找到正確的URL。
綜上所述:默認會配置STATIC_URL,在模板中推薦使用{%static 'sample.css'%} 這種方式!
在這裏還須要強調的是,在開發階段,Django使用的是內建的一個靜態文件服務器,雖然在生產環境中也可使用,可是它既不穩定也不安全。更好的方式是使用提供web服務的服務器如apache來服務靜態文件。這須要你首先上傳代碼到服務器,而後運行collectstatic命令:python manage.py collectstatic 而後配置web服務器來爲靜態文件服務,如對Apache2進行配置。
如何實現動態生成二級菜單
一級菜單,在數據庫加字段;
二級菜單,在權限表中,
表設計以下:
class Menu(models.Model): """ 菜單 """ title = models.CharField(verbose_name='菜單', max_length=32) icon = models.CharField(verbose_name='圖標', max_length=32) 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) menu = models.ForeignKey(verbose_name='菜單', to='Menu', null=True, blank=True, help_text='null表示非菜單') def __str__(self): return self.title
完整models.py以下:
from django.db import models class Menu(models.Model): """ 菜單 """ title = models.CharField(verbose_name='菜單', max_length=32) icon = models.CharField(verbose_name='圖標', max_length=32) 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) menu = models.ForeignKey(verbose_name='菜單', to='Menu', null=True, blank=True, help_text='null表示非菜單') 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