新建項目
models:
from django.db import models from django.contrib.auth.models import User # Create your models here. class Customers(models.Model): name = models.CharField(max_length=20, verbose_name='姓名') phone = models.CharField(max_length=15, verbose_name='電話') owner = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name='所屬用戶') def __str__(self): return self.name class Meta: verbose_name = '客戶表' verbose_name_plural = verbose_name permissions = ( ('show_all_customer', '查看所有客戶'), ('show_own_customer', '查看自己的客戶') )
‘show_all_customer’:這個是需要留意一下的,后面要用到. django的權限匹配 request.user.has_prem(“app.show_all_customer”) 就是將 app名 和 這個名稱用.連接之后匹配的。
‘查看所有客戶’ 這個就是顯示在后台權限列表里的描述。
這里只列舉兩個權限簡單說明一下用法,一個是查看所有客戶,一個是查看自己的客戶。
views:
from django.shortcuts import render from app.models import Customers from app.perm_check import check_permission # Create your views here. def show_all(request): customer_list = Customers.objects.all() return render(request, 'app/list.html', locals()) def show_own(request): uid = request.GET.get('uid', None) if uid: customer_list = Customers.objects.filter(owner_id=uid) return render(request, 'app/list.html', locals())
urls:
假設:訪問所有客戶列表 http://localhost:8000/all
訪問自己的客戶列表需要加參數uid , http://localhost:8000/own/?uid=2
from django.contrib import admin from django.urls import path from app.views import show_all, show_own urlpatterns = [ path('admin/', admin.site.urls), path('all/', show_all, name='show_all'), path('own/', show_own, name='show_own'), ]
settings.py中添加應用“app”, 我取的名字叫app. 並設置模版目錄 “templates”.
同步數據庫,並創建超級管理員
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
啟動項目,進入后台,添加數據
用戶 zhangsan, lisi給予登錄后台的權限,登錄了后台,就等於用戶已經登錄了,訪問其它非后台頁面也是登錄狀態。
權限設計
app目錄下新建 prem_list.py文件
perm_list = { 'app_show_all_customer': ['show_all', 'GET', []], 'app_show_own_customer': ['show_own', 'GET', ['uid',]] }
大體思路是這樣: 請求過來之后,先到prem_list中去匹配 ‘show_all’這樣的url_name, 然后再匹配 請求方法,再去列表中 匹配參數,如果都匹配上了,說明有給設置權限。那么再用request.user.has_perm()方法確定權限是否跟當前用戶綁定了,如果綁定了說明有權限。
寫一個權限檢測的方法,和一個裝飾器
app/perm_check.py
from django.urls import resolve from django.shortcuts import render from app.perm_list import perm_list def check(request, *args, **kwargs): url_obj = resolve(request.path_info) url_name = url_obj.url_name print('>>>>:', '權限匹配') if request.user.is_superuser: return True if url_name: url_method = request.method for k, v in perm_list.items(): per_url_name = v[0] per_method = v[1] per_args = v[2] args_match = False #匹配perm_list中的權限 if per_url_name == url_name and url_method == per_method: method_func = getattr(request, url_method) for arg in per_args: if method_func.get(arg): args_match = True else: args_match = False break else: args_match = True #prem_list權限匹配上了 if args_match: app_name, perm_name = k.split('_', 1) perm_str = '%s.%s' % (app_name, perm_name) print('>>>>: ', perm_name) if request.user.has_perm(perm_str): return True else: return False else: return False else: return False #沒有匹配上權限,默認不允許 #裝飾器 def check_permission(fun): def inner(request, *args, **kwargs): if check(request, *args, **kwargs): return fun(request, *args, **kwargs) return render(request, 'app/403.html', locals()) return inner
權限到這就寫完了。
模版
list.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> <tr> <th>姓名</th> <th>電話</th> <th>所屬用戶</th> </tr> {% for c in customer_list %} <tr> <td>{{ c.name }}</td> <td>{{ c.phone }}</td> <td>{{ c.owner }}</td> </tr> {% endfor %} </table> </body> </html>
403.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> 403 </div> </body> </html>
現在給兩個視圖加上裝飾器,檢測 權限
from django.shortcuts import render from app.models import Customers from app.perm_check import check_permission # Create your views here. @check_permission def show_all(request): customer_list = Customers.objects.all() return render(request, 'app/list.html', locals()) @check_permission def show_own(request): uid = request.GET.get('uid', None) if uid: customer_list = Customers.objects.filter(owner_id=uid) return render(request, 'app/list.html', locals())
給zhangsan分配查看所有客戶的權限 ,lisi分配 查看自己客戶 的權限 ,測試 一下
使用zhangsan登錄后台后 :
查看所有客戶
查看自己的客戶:
再使用lisi登錄后台:
這里發現一個問題,手動改變uid的值 后,lisi也能看到zhangsan的客戶,這就不符合要求了。
要解決這個問題,可以使用勾子函數的方法 。
定義勾子函數
app/perm_hook.py
def own_hook(request): uid = request.GET.get('uid', None) if uid == str(request.user.id): return True return False
修改 app/perm_list.py
from app import perm_hook perm_list = { 'app_show_all_customer': ['show_all', 'GET', []], 'app_show_own_customer': ['show_own', 'GET', ['uid',], perm_hook.own_hook] }
修改 app/perm_check.py
from django.urls import resolve from django.shortcuts import render from app.perm_list import perm_list def check(request, *args, **kwargs): url_obj = resolve(request.path_info) url_name = url_obj.url_name print('>>>>:', '權限匹配') if request.user.is_superuser: return True if url_name: url_method = request.method for k, v in perm_list.items(): per_url_name = v[0] per_method = v[1] per_args = v[2] args_match = False #匹配perm_list中的權限 if per_url_name == url_name and url_method == per_method: method_func = getattr(request, url_method) for arg in per_args: if method_func.get(arg): args_match = True else: args_match = False break else: args_match = True hook_match = True if len(v) >= 4: hook_func = v[3] hook_match = hook_func(request) #prem_list權限匹配上了 if args_match and hook_match: app_name, perm_name = k.split('_', 1) perm_str = '%s.%s' % (app_name, perm_name) print('>>>>: ', perm_name) if request.user.has_perm(perm_str): return True else: return False else: return False else: return False else: return False #沒有匹配上權限,默認不允許 #裝飾器 def check_permission(fun): def inner(request, *args, **kwargs): if check(request, *args, **kwargs): return fun(request, *args, **kwargs) return render(request, 'app/403.html', locals()) return inner
修改完之后,啟動應用 ,再用lisi訪問zhangsan的客戶:
發現已經 不能訪問了,再訪問一下自己的客戶: