rbac组件之权限操作(四)

对于权限表的操作有两种方式,第一种是一个个的权限进行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'),
...

后台进行处理

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字段旁边
PermissionModelForm
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'))

第二种方式是批量增加

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
MultiPermissionForm

 利用formset生成批量数据

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,
        }
    )
View Code

获取路由系统中的url

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
View Code
原文地址:https://www.cnblogs.com/shenjianping/p/10960663.html