对于权限表的操作有两种方式,第一种是一个个的权限进行curd,另外一种是批量操作,自动发现django程序中的路由,进行批量curd,首先介绍第一种方式。
因为在列出菜单时,已经将权限列表列出来了,所以权限包括增加、修改以及删除操作
urls.py
... re_path(r'^permissions/add/$', PermissionAddView.as_view(), name='permissions_add'), re_path(r'^permissions/edit/(?P<pid>\d+)/$', PermissionEditView.as_view(), name='permissions_edit'), re_path(r'^permissions/dell/(?P<pid>\d+)/$', PermissionDelView.as_view(), name='permissions_del'), re_path(r'^multi/permissions/$', multi_permissions, name='multi_permissions'), ...
后台进行处理
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
from django import forms from rbac import models class PermissionModelForm(forms.ModelForm): class Meta: model=models.Permission fields='__all__' widgets = { 'title': forms.TextInput(attrs={'placeholder': '请输入权限名称', 'class': 'form-control'}), 'url': forms.TextInput(attrs={'placeholder': '请输入url', 'class': 'form-control'}), 'name': forms.TextInput(attrs={'placeholder': '请输入url名称', 'class': 'form-control'}), 'parent': forms.Select(attrs={'class': 'form-control'}), 'menu':forms.Select(attrs={'class': 'form-control'}), } help_texts={ 'parent':'父级权限,无法作为菜单的权限才需要选择。', 'menu':'选中,表示该权限可以作为菜单;否则,不可做菜单。' } error_messages ={ 'title':{ 'required':'该字段不能为空' } } def clean(self): menu=self.cleaned_data['menu'] parent=self.cleaned_data['parent'] if menu and parent: self.add_error('menu','菜单和根权限同时只能选择一个')#错误标注在menu字段旁边
from django.shortcuts import render,redirect,HttpResponse from django.views import View from rbac.models import * from rbac.forms.permissions import PermissionModelForm from django.urls import reverse class PermissionAddView(View): def get(self,request): form = PermissionModelForm() return render(request,'rbac/permission_add.html',{'form':form}) def post(self,request): form=PermissionModelForm(data=request.POST) if form.is_valid(): form.save() return redirect(reverse('rbac:menus_list')) return render(request,'rbac/permission_add.html',{'form':form}) class PermissionEditView(View): def get(self,request,pid): permission_obj=Permission.objects.filter(id=pid).first() if not permission_obj: return HttpResponse('该权限不存在') form=PermissionModelForm(instance=permission_obj) return render(request,'rbac/permission_edit.html',{'form':form}) def post(self,request,pid): permission_obj=Permission.objects.filter(id=pid).first() form=PermissionModelForm(data=request.POST,instance=permission_obj) if form.is_valid(): form.save() return redirect(reverse('rbac:menus_list')) return render(request, 'rbac/permission_edit.html', {'form': form}) class PermissionDelView(View): def get(self,request,pid): Permission.objects.filter(id=pid).first().delete() return redirect(reverse('rbac:menus_list'))
第二种方式是批量增加
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class MultiPermissionForm(forms.Form): id = forms.IntegerField( widget=forms.HiddenInput(), required=False ) title = forms.CharField( widget=forms.TextInput(attrs={'class': "form-control"}) ) url = forms.CharField( widget=forms.TextInput(attrs={'class': "form-control"}) ) name = forms.CharField( widget=forms.TextInput(attrs={'class': "form-control"}) ) menu_id = forms.ChoiceField( choices=[(None, '-----')], widget=forms.Select(attrs={'class': "form-control"}), required=False, ) parent_id = forms.ChoiceField( choices=[(None, '-----')], widget=forms.Select(attrs={'class': "form-control"}), required=False, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['menu_id'].choices += models.Menu.objects.values_list('id', 'title') self.fields['parent_id'].choices += models.Permission.objects.filter(parent__isnull=True).exclude( menu__isnull=True).values_list('id', 'title') def clean_parent_id(self): menu = self.cleaned_data.get('menu_id') parent_id = self.cleaned_data.get('parent_id') if menu and parent_id: raise forms.ValidationError('菜单和根权限同时只能选择一个') return parent_id
利用formset生成批量数据
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
from rbac.forms.muti_permissions import MultiPermissionForm from django.shortcuts import render from django.forms import formset_factory,modelform_factory from rbac import models from rbac.services.routes import * def multi_permissions(request): """ 批量操作权限 :param request: :return: """ post_type = request.GET.get('type') MultiPermissionFormSet = formset_factory(MultiPermissionForm,extra=0) generate_formset = None update_formset = None if request.method == 'POST' and post_type == 'generate': print('request.post',request.POST) formset = MultiPermissionFormSet(request.POST) if formset.is_valid(): for row_dict in formset.cleaned_data: models.Permission.objects.create(**row_dict) else: generate_formset = formset if request.method == 'POST' and post_type == 'update': formset = MultiPermissionFormSet(request.POST) if formset.is_valid(): for row_dict in formset.cleaned_data: permission_id = row_dict.pop('id') models.Permission.objects.filter(id=permission_id).update(**row_dict) else: update_formset = formset # 1.1 去数据库中获取所有权限 # [{},{}] permissions = models.Permission.objects.all().values('id', 'title', 'url', 'name', 'menu_id', 'parent_id') # {'rbac:menu_list':{},'rbac:menu_add':{..}} permisssion_dict = OrderedDict() for per in permissions: permisssion_dict[per['name']] = per # 1.2 数据库中有的所有权限name的集合 permission_name_set = set(permisssion_dict.keys()) # 2.1 获取路由系统中所有的URL # {'rbac:menu_list':{'url':.... },,,} router_dict = get_all_url_dict(ignore_namespace_list=['admin',]) for row in permissions: name = row['name'] if name in router_dict: router_dict[name].update(row) # 2.2 路由系统中的所有权限name的集合 router_name_set = set(router_dict.keys()) # 需要新建:数据库无、路由有 if not generate_formset: generate_name_list=router_name_set-permission_name_set generate_formset = MultiPermissionFormSet( initial=[row for name, row in router_dict.items() if name in generate_name_list] ) # 需要删除:数据库有、路由无 destroy_name_list = permission_name_set - router_name_set destroy_formset = [row for name, row in permisssion_dict.items() if name in destroy_name_list] # 需要更新:数据库有、路由有 if not update_formset: update_name_list = permission_name_set.intersection(router_name_set) update_formset = MultiPermissionFormSet( initial=[row for name, row in router_dict.items() if name in update_name_list] ) return render( request, 'rbac/multi_permissions.html', { 'destroy_formset': destroy_formset, 'update_formset': update_formset, 'generate_formset': generate_formset, } )
获取路由系统中的url
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import re from collections import OrderedDict from django.conf import settings from django.utils.module_loading import import_string from django.urls.resolvers import URLResolver, URLPattern def recursion_urls(pre_namespace, pre_url, valid_urlpattern_list, url_ordered_dict): """ 递归的去获取URL :param pre_namespace: namespace前缀,以后用户拼接name :param pre_url: url前缀,以后用于拼接url :param urlpatterns: 路由关系列表 :param url_ordered_dict: 用于保存递归中获取的所有路由 :return: """ for item in valid_urlpattern_list: if isinstance(item, URLPattern): # 非路由分发,讲路由添加到url_ordered_dict if not item.name: continue if pre_namespace: name = "%s:%s" % (pre_namespace, item.name,) else: name = item.name if not item.name: raise Exception('URL路由中必须设置name属性') url = pre_url + str(item.pattern) url_ordered_dict[name] = {'name': name, 'url': url.replace('^', '').replace('$', '')} elif isinstance(item, URLResolver): # 路由分发,递归操作 if pre_namespace: if item.namespace: namespace = "%s:%s" % (pre_namespace, item.namespace,) else: namespace = pre_namespace else: if item.namespace: namespace = item.namespace else: namespace = None recursion_urls(namespace, pre_url + str(item.pattern), item.url_patterns, url_ordered_dict) def get_all_url_dict(ignore_namespace_list=None): """ 获取项目中所有的URL(必须有name别名) :return: """ ignore_namespace_list=ignore_namespace_list or [] valid_urlpattern_list=[] url_ordered_dict = OrderedDict() urlpatterns_list= import_string(settings.ROOT_URLCONF).urlpatterns # from luff.. import urls for urlpattern in urlpatterns_list: if isinstance(urlpattern, URLResolver): if urlpattern.namespace in ignore_namespace_list: continue else: valid_urlpattern_list.append(urlpattern) valid_urlpattern_list.append(urlpattern) recursion_urls(None, '/', valid_urlpattern_list, url_ordered_dict) # 递归去获取所有的路由 return url_ordered_dict