- 01 上节回顾
- 02 后台管理布局
- 03 按钮权限控制的简单形式
- 04 修改表结构
- 05 重构数据结构
- 06 限制权限颗粒度
01 上节回顾
1.1 项目的组织架构;
1.2 项目组件的版本说明;
使用的是Django1.11.1与最新的Django有区别,请注意。另外Pycharm创建的Django项目一般都是最新的,2018版本Pycharm自带virtualenv环境,无需个人再次安装。如需执行Django版本,可在本机的Python解释器环境下,pip install django=="1.11.1",然后通过Pycharm创建Django项目的时候指定一下内置的Python解释器,见下图。
1.3 settings.py文件说明;
自行配置TEMPLATES中的DIRS;
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
settings.py
""" Django settings for s9day82_rbac project. Generated by 'django-admin startproject' using Django 1.11.1. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '0s(th#!ewf^xik5n&bqkqqjadz#q*vt+!hq(kzk5*-!t6@^0^i' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition 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', ] 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.service.rbac.ValidPermission', ] from django.middleware.security import SecurityMiddleware ROOT_URLCONF = 's9day82_rbac.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 's9day82_rbac.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/'
1.4 urls.py;
"""s9day82_rbac URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/$', views.users), url(r'^users/add', views.add_user), url(r'^roles/', views.roles), url(r'^login/', views.login), ]
1.5 views.py;
import re from django.shortcuts import render, HttpResponse # Create your views here. from rbac.models import * from rbac.service.permissions import * def users(request): user_list = User.objects.all() return render(request, "users.html", locals()) def add_user(request): return HttpResponse("Add User......") def roles(request): role_list = Role.objects.all() return render(request, "roles.html......", locals()) def login(request): if request.method == "POST": user_obj = request.POST.get("user") pwd = request.POST.get("pwd") user = User.objects.filter(name=user_obj, pwd=pwd).first() if user: # #################在session中注册用户ID###########################; request.session["user_id"] = user.pk initial_session(user, request) ''' 此处的values()相当于: temp = []#定义一个空列表; for role in user.roles.all();#values属性,相当于循环该对象[<Role: 保洁>, <Role: 销售>]> temp.append({ "title":role.title, "permissions__url":role.permissions.all() }) ''' return HttpResponse("登录成功!") return render(request, "login.html", locals())
1.6 models.py;
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) def __str__(self): return self.title
1.7 templates模板文件;
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>登录页面</h4> <form action="" method="post"> {% csrf_token %} 用户名:<input type="text" name="user"> 密码:<input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
roles.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Users</title> </head> <body> <h4>角色列表</h4> <ul> {% for role in role_list %} <p>{{ role }}</p> {% endfor %} </ul> </body> </html>
1.8 permissions.py
def initial_session(user, request): # #################在session注册权限列表###########################; # 查询当前登录用户的所有角色; ret = user.roles.all() print("ret", ret) # <QuerySet [<Role: 保洁>, <Role: 销售>]> # 查询当前用户的所有权限; permissions = user.roles.all().values( "permissions__url").distinct() # ret_role <QuerySet [{'permissions__url': '/users/'}, # {'permissions__url': '/users/add'}]> # 进行数据的处理,生成列表; permission_list = [] for item in permissions: permission_list.append(item["permissions__url"]) print("permission_list", permission_list) # permission_list ['/users/', '/users/add'] request.session["permission_list"] = permission_list
02 后台管理布局
login.html;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h4>登录页面</h4> <form action="" method="post"> {% csrf_token %} 用户名:<input type="text" name="user"> 密码:<input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
base.html;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <style> .header { width: 100%; height: 60px; background-color: #336699; } .menu { background-color: bisque; position: fixed; top: 60px; bottom: 0; left: 0; width: 200px; } .content { position: fixed; top: 60px; bottom: 0; right: 0; left: 200px; overflow: auto; padding: 30px; } </style> </head> <body> <div class="header"> <p>{{ user.name }}</p> </div> <div class="contain"> <div class="menu">11</div> <div class="content "> {% block con %} {% endblock %} </div> </div> </body> </html>
users.html;
{% extends 'base.html' %} {% block con %} <h4>用户列表</h4> {% if per.add %} <a href="/users/add/" class="btn btn-primary">添加用户</a> {% endif %} <table class="table table-bordered table-striped"> <thead> <tr> <th>序号</th> <th>姓名</th> <th>角色</th> <th>操作</th> </tr> </thead> <tbody> {% for user in user_list %} <tr> <td>{{ forloop.counter }}</td> <td>{{ user.name }}</td> <td> {% for role in user.roles.all %} {{ role.title }} {% endfor %} </td> <td> {% if per.delete %} <a href="/users/delete/{{ user.pk }}" class="btn btn-danger">删除</a> {% endif %} {% if per.edit %} <a href="" class="btn btn-info">编辑</a> {% endif %} </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
roles.html;
{% extends 'base.html' %} {% block con %} <h4>角色列表</h4> {% if per.add %} <a href="" class="btn btn-primary">添加角色</a> {% endif %} <table class="table table-bordered table-striped"> <tbody> {% for role in role_list %} <tr> <td>{{ forloop.counter }}</td> <td>{{ role.title }}</td> <td> <a href="/users/delete/{{ user.pk }}" class="btn btn-danger">删除</a> <a href="" class="btn btn-info">编辑</a> </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
03 按钮权限控制的简单形式
1、引入CDN的Bootstrap;
<meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
04 修改表结构
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("PermissionGroup", default=1) def __str__(self): return self.title class PermissionGroup(models.Model): title = models.CharField(max_length=32) def __str__(self): return self.title
05 重构数据结构
06 限制权限颗粒度
settings.py;
""" Django settings for s9day82_rbac project. Generated by 'django-admin startproject' using Django 1.11.1. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '0s(th#!ewf^xik5n&bqkqqjadz#q*vt+!hq(kzk5*-!t6@^0^i' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition 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', ] 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.service.rbac.ValidPermission', ] from django.middleware.security import SecurityMiddleware ROOT_URLCONF = 's9day82_rbac.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 's9day82_rbac.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/'
urls.py;
"""s9day82_rbac URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/$', views.users), url(r'^users/add', views.add_user), url(r'^users/delete/(\d+)', views.del_user), url(r'^roles/', views.roles), url(r'^login/', views.login), ]