-
01 权限菜单显示
-
02 Django路径的自动添加问题
-
03 原生form实现增删改查
-
04 modelform实现增删改查
01 权限菜单显示
1.1 优先查找项目中的templates,如果没有,然后再去查找应用中的templates下的模板文件;
1.1.2 如果每个应用下都有相同名称的templates或者templatetags,会根据应用的创建顺序进行查找;
1.1.3 为避免以上情况发生,建议在templates或者templatestags目录下分别建立应用名称,然后再放置.html模板文件或者my_tag.py文件;
整个项目的完整目录结构:
总结一下整个项目的开发流程:
- 使用Pycharm创建项目,进行项目的命名
- 使用Pycharm下的Tools》Run manage.py task启动shell窗口
- startapp app01
- startapp rbac(Role-Based Access Control,即基于角色的访问权限控制)详情见:https://baike.baidu.com/item/RBAC/1328788?fr=aladdin
- settings.py配置文件进行TEMPLATES以及INSTALLED_APPS的添加配置;
- urls.py的配置;
- app01/views.py的配置;
- rbac/models.py的配置并进行数据库迁移操作 makemigrationsmigrate
- rbac/admin.py的注册配置,并引入class类;
- 进行程序的解耦合操作,进行rbac/service/permissions.py以及rbac/service/rbac.py的配置;
- 进行自定义templatetags的自定义,my_tags.py的配置;
- 分别添加base.html menu.html users.html roles.html 等模板文件,进行extends、include、block等方法进行关联;
- 将基础模板文件从根目录的templates目录迁移至rbac/templates目录下
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), ]
views.py
import re from django.shortcuts import render, HttpResponse # Create your views here. from rbac.models import * from rbac.service.permissions 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") # print(permission_list) # ['/users/', '/users/add', '/users/delete/(\d+)', '/users/edit/(\d+)'] # 查询当前登录人的名字; id = request.session.get("user_id") user = User.objects.filter(id=id).first() per = Per(request.actions) return render(request, "users.html", locals()) def add_user(request): return HttpResponse("Add User......") def del_user(request, id): return HttpResponse("Delete User..." + id) def roles(request): role_list = Role.objects.all() per = Per(request.actions) 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")
permissions.py
def initial_session(user, request): # 方案1 # #################在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 # 方案2; permissions = user.roles.all().values("permissions__url", "permissions__group_id", "permissions__action").distinct() print("permissions ", 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) request.session["permission_dict"] = permission_dict # 注册菜单权限; permissions = user.roles.all().values("permissions__url", "permissions__action", "permissions__group__title").distinct() print("permissions", 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) request.session["menu_permission_list"] = menu_permission_list
admin.py
from django.contrib import admin # Register your models here. from .models import * class PerConfig(admin.ModelAdmin): list_display = ["title", "url", "group", "action"] admin.site.register(User) admin.site.register(Role) admin.site.register(Permission, PerConfig) admin.site.register(PermissionGroup)
rbac.py
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse, redirect import re # 自定义中间件! class ValidPermission(MiddlewareMixin): def process_request(self, request): # 当前访问权限; current_path = request.path_info # 1、校验权限,是否是与白名单; 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_list = request.session.get( # "permission_list", # []) # permission_list ['/users/', '/users/add', '/users/delete/(\d+)', '/users/edit/(\d+)'] # # flag = False # for permission in permission_list: # permission = "^%s$" % permission # ret = re.match(permission, current_path) # if ret: # flag = True # break # if not flag: # # return None # 3、校验是否登录; permission_dict = request.session.get("permission_dict") 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("没有访问权限!")
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) 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
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; } .menu_btn { font-size: 18px; text-align: center; padding: 50px 0; } </style> </head> <body> <div class="header"> <p>{{ user.name }}</p> </div> <div class="contain"> {% load my_tags %} <div class="menu"> {% get_menu request %} </div> <div class="content "> {% block con %} {% endblock %} </div> </div> </body> </html>
menu.html
<div> {% for item in menu_permission_list %} <p class="menu_btn"><a href="{{ item.0 }}">{{ item.1 }}</a></p> {% endfor %} </div>
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="/users/edit/{{ user.pk }}" class="btn btn-info">编辑</a> {% endif %} </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
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>
my_tags.py
from django import template register = template.Library() @register.inclusion_tag("menu.html") def get_menu(request, ): # 获取当前用户可以放到菜单栏中的权限; menu_permission_list = request.session["menu_permission_list"] return {"menu_permission_list": menu_permission_list}
02 Django路径的自动添加问题
2.1 settings.py文件中,APPEND_SLASH默认值为True;
2.2 在setings.py中,将APPEND_SLASH调整为False;
#设置项是否开启URL访问地址后面不为/跳转至带有/的路径;
03 原生form实现增删改查
3.1 创建Django项目并制定Python解释器下安装的Django==“1.11.1” version;
3.2 基于form实现的图书管理系统的增删改查步骤;
- 创建django项目并指定app及Python内置解释器;
- 检查settings.py是否配置了TEMPLATES以及INSTALLED_APPS;
- 配置urls.py;
- 编写视图函数views.py;
- 编写ORM——models.py;
- 进行admin.py的注册;
- 通过Pycharm下的Run manage.py task进行数据库的迁移以及createsuperuser操作;
- 编写模板——add.htmlooks.htmledit.html;
urls.py;
"""FormsDemo 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'^books/', views.books), url(r'^book/add', views.add_book), url(r'^book/edit/(d+)', views.edit_book), ]
views.py;
from django.shortcuts import render, redirect # Create your views here. from .models import * def books(request): book_list = Book.objects.all() return render(request, "books.html", locals()) def add_book(request): if request.method == "POST": title = request.POST.get("title") price = request.POST.get("price") date = request.POST.get("date") publish_id = request.POST.get("publish_id") author_pk_list = request.POST.getlist("author_pk_list") book_obj = Book.objects.create(title=title, price=price, date=date, publish_id=publish_id) book_obj.authors.add(*author_pk_list) return redirect('/books/') publish_list = Publish.objects.all() author_list = Author.objects.all() return render(request, "add.html", locals()) def edit_book(request, edit_book_id): if request.method == "POST": title = request.POST.get("title") price = request.POST.get("price") date = request.POST.get("date") publish_id = request.POST.get("publish_id") author_pk_list = request.POST.getlist("author_pk_list") Book.objects.filter(pk=edit_book_id).update(title=title, price=price, date=date, publish_id=publish_id) book_obj = Book.objects.filter(pk=edit_book_id).first() book_obj.authors.set(author_pk_list) return redirect('/books/') edit_book = Book.objects.filter(pk=edit_book_id).first() publish_list = Publish.objects.all() author_list = Author.objects.all() return render(request, "edit.html", locals())
models.py;
from django.db import models # Create your models here. class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2) # 999999.99 date = models.DateField() publish = models.ForeignKey("Publish") authors = models.ManyToManyField("Author") def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name
admin.py;
from django.contrib import admin # Register your models here. from .models import * admin.site.register(Book) admin.site.register(Author) admin.site.register(Publish)
books.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Books</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <a href="/book/add"><button>添加书籍</button></a> <ul> <table border="1"> {% for book in book_list %} <tr> <td>{{ book.title }}</td> <td>{{ book.price }}</td> <td>{{ book.date|date:"Y-m-d" }}</td> <td>{{ book.publish.name }}</td> <td>{{ book.authors.all }}</td> <td><a href="/book/edit/{{ book.pk }}"><button>编辑</button></a></td> </tr> {% endfor %} </table> </ul> </body> </html>
add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>add</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h3>添加页面</h3> <form action="" method="post"> {% csrf_token %} <p>书籍名称<input type="text" name="title"></p> <p>价格<input type="text" name="price"></p> <p>日期<input type="date" name="date"></p> <p>出版社 <select name="publish_id" id=""> {% for publish in publish_list %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endfor %} </select> </p> <p>作者 <select name="author_pk_list" id="" multiple> {% for author in author_list %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endfor %} </select> </p> <input type="submit"> </form> </body> </html>
edit.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>add</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h3>编辑页面</h3> <form action="" method="post"> {% csrf_token %} <p>书籍名称<input type="text" name="title" value="{{ edit_book.title }}"></p> <p>价格<input type="text" name="price" value="{{ edit_book.price }}"></p> <p>日期<input type="date" name="date" value="{{ edit_book.date|date:"Y-m-d" }}"></p> <p>出版社 <select name="publish_id" id=""> {% for publish in publish_list %} {% if edit_book.publish == publish %} <option selected value="{{ publish.pk }}">{{ publish.name }}</option> {% else %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endif %} {% endfor %} </select> </p> <p>作者 <select name="author_pk_list" id="" multiple> {% for author in author_list %} {% if author in edit_book.authors.all %} <option selected value="{{ author.pk }}">{{ author.name }}</option> {% else %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endif %} {% endfor %} </select> </p> <input type="submit"> </form> </body> </html>
04 modelform实现增删改查
4.1 使用forms组件代替form表单;
class BookForm(forms.Form): title = forms.CharField(max_length=32, label="书籍名称") price = forms.DecimalField(max_digits=8, decimal_places=2, label="价格") # 999999.99 date = forms.DateField(label="日期", widget=widgets.TextInput(attrs={"type": "date"}) ) # gender = forms.ChoiceField(choices=((1, "男"), (2, "女"), (3, "其他"),)) # publish = forms.ChoiceField(choices=Publish.objects.all().values_list("pk", "name")) publish = forms.ModelChoiceField(queryset=Publish.objects.all()) authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
4.2 基于ModelForm进行精简开发;
views.py
from django.shortcuts import render, redirect # Create your views here. from .models import * from django import forms from django.forms import widgets from django.forms import ModelForm from django.forms import widgets as wid ''' class BookForm(forms.Form): title = forms.CharField(max_length=32, label="书籍名称") price = forms.DecimalField(max_digits=8, decimal_places=2, label="价格") # 999999.99 date = forms.DateField(label="日期", widget=widgets.TextInput(attrs={"type": "date"}) ) # gender = forms.ChoiceField(choices=((1, "男"), (2, "女"), (3, "其他"),)) # publish = forms.ChoiceField(choices=Publish.objects.all().values_list("pk", "name")) publish = forms.ModelChoiceField(queryset=Publish.objects.all()) authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) ''' class BookForm(ModelForm): class Meta: model = Book fields = "__all__" # fields = ["title", "price"] labels = { "title": "书籍名称", "price": "价格", "date": "书籍日期", "publish": "出版社", "authors": "作者", } widgets = { "title": wid.TextInput(attrs={"class": "form-control"}), "price": wid.TextInput(attrs={"class": "form-control"}), "date": wid.TextInput(attrs={"class": "form-control"}), "publish": wid.TextInput(attrs={"class": "form-control"}), "authors": wid.TextInput(attrs={"class": "form-control"}), } def books(request): book_list = Book.objects.all() return render(request, "books.html", locals()) def add_book(request): if request.method == "POST": form = BookForm(request.POST) if form.is_valid(): form.save() return redirect("/books/") form = BookForm() return render(request, "add.html", locals()) def edit_book(request, edit_book_id): edit_book = Book.objects.filter(pk=edit_book_id).first() if request.method == "POST": form = BookForm(request.POST, instance=edit_book) form.save() return redirect("/books/") form = BookForm(instance=edit_book) return render(request, "edit.html", locals())
add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>add</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"> </head> <body> <h3>添加页面</h3> <div class="col-md-4 col-md-offset-3"> {% include 'form.html' %} </div> </body> </html>
books.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Books</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <a href="/book/add"><button>添加书籍</button></a> <ul> <table border="1"> {% for book in book_list %} <tr> <td>{{ book.title }}</td> <td>{{ book.price }}</td> <td>{{ book.date|date:"Y-m-d" }}</td> <td>{{ book.publish.name }}</td> <td>{{ book.authors.all }}</td> <td><a href="/book/edit/{{ book.pk }}"><button>编辑</button></a></td> </tr> {% endfor %} </table> </ul> </body> </html>
edit.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>add</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h3>编辑页面</h3> {% include 'form.html' %} </body> </html>
form.html
<form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> {{ field.label }} {{ field }} </div> {% endfor %} <input type="submit"> </form>