1. 角色、菜单、权限的增删该查 1. ModelForm增删改查 2. 增加和编辑使用同一个视图函数 Form() 1. 生成获取用户输入的标签 2. 对用户输入的内容做校验 3. 保留输入的内容同时展示错误提示信息 ModelForm() 1. 不需要自己写类中字段 2. 编辑的时候可以使用instance参数直接把要修改的实例传到form表单 1. 生成获取用户输入的标签时能够把instance的属性直接当成默认值 2. POST提交的时候可以直接调用save()保存数据 FormSet() from django.forms import formset_factory ModelFormSet() from django.forms import modelformset_factory ORM复习(对象关系映射) 1. 对应关系 ORM 数据库 类 <--> 数据表 属性 <--> 字段 对象 <--> 数据行 2. 爬取icon图标 1. requests 2. beautifulsoup4 3. 权限批量录入 1. 集合的操作 1. 差集、交集、反交集 2. 获取一个Django项目的所有路由 rbac/utils/reload_routes.py 3. 页面上将没有入库的路由数据直接加载到addformset中 4. formset使用的三个要点 1. {{ formsetobj.management_form }} --> 管理form(提交数据的时候告诉后端我提交了多少条数据) 2. 每一条数据中都要有form_obj.id(添加的时候不需要,编辑的时候需要) 3. form表单的那三要素 2. 今日内容
权限的批量操作
项目复杂之后URL有很多
1. 自动根据项目的URL录入路由信息(能自动获取路由别名和URL)
1. Django中的路由
二级路由 --> rbac:menu_list #:号就是分割命名空间的,也就是rbacapp的urls.py中还可以再include包另外的路由
三级路由 --> rbac:menu:menu_list
2. 自动录入写完之后会有三种情况:
1. 权限表里有,项目里面没有
2. 权限表里有,项目里面也有
3. 权限表里没有,项目里面有--如加新功能app
3. formset提交数据三要素
1. form表单
2. submit按钮
3. formset_obj.management_form
4. 因为使用的是Formset而不是ModelFormset所以不能调用save()保存,需要自己手动创建数据
1. 批量录入权限2 1. formset和modelformset的使用 2. 集合的操作 3. 如何巧妙的区分同一个action两次不同的POST请求 2. jQuery中文文档:http://jquery.cuishifeng.cn/ 3. 批量更新权限 1. 页面实现 1. Bootstrap、jQuery 2. 页面更新 1. 两个form表单POST提交数据 永远都唔好低估自己! 不负此生,前程似锦!
一.批量录入权限
我想实现的是利用formset实现的是只要你访问某个url,就能把当前项目里所有的路由:第一部分项目里没有但权限表里没有的放在下图1新增中。第二部分是我权限表和项目里都有的,放在下图2更新权限中。第三部分是我数据库里有但项目里没有的,放在如下图3中,此三图在一个页面实现操作管理。
(1)rbac/utils/reload_routes.py:自动录入脚本
from django.conf import settings from django.utils.module_loading import import_string #module_loading是加载模块 from django.urls import RegexURLResolver from collections import OrderedDict #per_namespae是前一个命名空间,pre_url是上一级路由,urlpatterns路由表达式,生成一字典 def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict): for item in urlpatterns: # 如果是嵌套的URL if isinstance(item, RegexURLResolver): if pre_namespace: if item.namespace: #如果是嵌套的路由那就拿上一级路由命名空间给它拼起来,如果没有上一级则不用拼接直接赋值 namespace = '{}:{}'.format(pre_namespace, item.namespace,) else: namespace = pre_namespace else: if item.namespace: namespace = item.namespace else: namespace = None # 如果还有嵌套的三级、四级...路由就递归的执行 recursion_urls(namespace, pre_url + item.regex.pattern, item.url_patterns, url_ordered_dict) # 普通URL else: if pre_namespace: name = '{}:{}'.format(pre_namespace, item.name,) else: name = item.name if not item.name: raise Exception('URL路由中必须设置name属性') url = pre_url + item.regex.pattern # 把分析出来的每一条路由都以 命名空间:路由别名 为key 存到有序字典里 url_ordered_dict[name] = {'name': name, 'url': url.replace('^', '').replace('$', '')} def get_all_url_dict(ignore_namespace_list=None):#忽略命名空间的列表作为参数但它是可变类型所以设为none好 """获取路由中""" ignore_list = ignore_namespace_list or [] # 生成一个有序的字典 url_ordered_dict = OrderedDict() # 导入Django的路由配置:import_string是根据一字符串导入的模块 root_url_conf = import_string(settings.ROOT_URLCONF) # 生成一个空列表 urlpatterns = [] # for循环项目所有的路由--luffy_permission/urls.py中的所有路由列表--一级路由 for item in root_url_conf.urlpatterns: #如果路由是regexurlresolver嵌套路由类型且命名空间在忽略的列表中就continue跳过这次循环 if isinstance(item, RegexURLResolver) and item.namespace in ignore_list: continue urlpatterns.append(item) # 调用上方的函数分析并收集项目中的路由,None是pre_namespace参数(前一个命名空间--在django的路由里它可以嵌套好几层) recursion_urls(None, '/', urlpatterns, url_ordered_dict) return url_ordered_dict
(2)rbac/urls.py中:
#权限批量录入
url(r'^permission_entry/$', views.permission_entry, name='permission_entry'),
(3)rbac/views.py中:
from rbac.utils import permission ,reload_routes from rbac.forms import RoleForm, MenuForm, PermissionForm from django.forms import modelform_factory, formset_factory # 权限录入 def permission_entry(request): # 项目里面所有的路由--当你一访问permission_entry时调用get_all_dict方法 all_urls = reload_routes.get_all_url_dict(ignore_namespace_list=['admin', ]) # 数据库中权限表中存储的所有路由 all_permissions = Permission.objects.all() # 用集合去判断 # 项目中所有路由的集合 project_url_set = set(all_urls.keys()) # 数据库中permission表中的路由集合 db_url_set = set([i.name for i in all_permissions]) # 项目中有,数据库中没有 only_in_project = project_url_set - db_url_set # 这些路由应该是等待添加到数据库中权限表里面的数据 AddFormset = formset_factory(PermissionForm, extra=0) add_formset_obj = AddFormset(initial=[v for k, v in all_urls.items() if k in only_in_project]) if request.method == 'POST': add_formset_obj = AddFormset(request.POST) if add_formset_obj.is_valid(): # 手动创建permission objs = (Permission(**item) for item in add_formset_obj.cleaned_data) Permission.objects.bulk_create(objs) return redirect(reverse('rbac:permission_entry')) return render( request, 'rbac/permission_entry.html', {'add_formset_obj': add_formset_obj} )
(4)rbac/templates/rbac/permission_entry.html中:
放三个小面板.
{% extends 'layout.html' %} {% block content %} <div class="container-fluid"> <div class="row"> <div class="col-md-12"> <form action="" method="post"> {% csrf_token %} <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">添加权限 <button class="btn btn-success btn-xs pull-right" type="submit">添加</button> </h3> </div> <div class="panel-body"> <p>那些只在项目中,还没来得及太能加到permission表中的路由数据</p> <table class="table table-bordered"> <thead> <tr> <th>#</th> <th>title</th> <th>url</th> <th>show</th> <th>name</th> <th>menu</th> </tr> </thead> <tbody> {% for form_obj in add_formset_obj %} {{ add_formset_obj.management_form }} <tr> {{ form_obj.id }} <td>{{ forloop.counter }}</td> <td>{{ form_obj.title }} <span>{{ form_obj.title.errors.0 }}</span></td> <td>{{ form_obj.url }}</td> <td>{{ form_obj.show }}</td> <td>{{ form_obj.name }}</td> <td>{{ form_obj.menu }}</td> </tr> {% endfor %} </tbody> </table> </div> </div> </form> </div> </div> </div> {% endblock %}
3