首页 > 其他分享 >Django之权限管理

Django之权限管理

时间:2024-03-26 10:45:39浏览次数:20  
标签:__ 管理 url menu request Django 权限 id permissions

一, 引入

1.为什么要有权限?

2.为什么要开发权限的组件?

3.在web开发中,什么是权限?

4.表结构的设计

权限表

ID URL
1 /user_list/
2 /customer_list/

用户表

ID USER_NAME
1 root
2 root 2

角色/用户组表

ID
1 销售
2 开发

用户与角色的关系表

ID USER_ID 角色ID
1 1 1
2 1 2
3 2 1
4 2 2

角色与权限的关系表

ID 角色ID 权限ID
1 1 1
2 1 2
3 2 1
4 2 2

models:

from django.db import models


# 权限表
class Permission(models.Model):
    url = models.CharField(max_length=108, verbose_name='权限')


# 角色表
class Role(models.Model):
    name = models.CharField(max_length=108, verbose_name='角色')
    permissions = models.ManyToManyField('Permission', verbose_name='角色所拥有的权限', related_name='roles')


# 用户表
class UserInfo(models.Model):
    username = models.CharField(max_length=32, verbose_name='用户名')
    password = models.CharField(max_length=32, verbose_name='密码')
    roles = models.ManyToManyField('Role', verbose_name='用户所拥有的角色', related_name='users')

基本流程:

二, admin的展示

from django.contrib import admin
from rbac import models

# 配置类
class PermissionAdmin(admin.ModelAdmin):
    # 展示
    list_display = ['title', 'url']
    # 可编辑
    list_editable = ['url']

admin.site.register(models.Role)
admin.site.register(models.Permission, admin_class=PermissionAdmin)
admin.site.register(models.UserInfo)

三, 记录登录状态与权限

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect, reverse
from django.conf import settings
import re

def login(request):
    error = ''
    if request.method == 'POST':
        # 获取用户名和密码
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 数据库校验用户名密码是否正确
        user_obj = models.UserInfo.objects.filter(username=username, password=password).first()
        if not user_obj:
            # 校验失败,返回登录页面
            error = '用户名或密码错误'
        else:
            # 登录成功
            # 查询当前用户的权限信息
            # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
            permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url').distinct()
            # 保存权限信息
            request.session['permission'] = list(permission)
            request.session['is_login'] = 1
            # 重定向去首页
            return redirect('index')

    return render(request, 'login.html', {'error': error})

四, 中间件校验权限

class Rbac(MiddlewareMixin):

    def process_request(self, request):
        # 获取当前访问的地址
        url = request.path_info
        # 白名单
        for i in settings.WHITE_LIST:
            if re.match(i, url):
                return
        # 登陆状态的校验
        is_login = request.session.get('is_login')
        if not is_login:
            return redirect('login]')
        # 免认证校验
        for i in settings.PASS_AUTH_LIST:
            if re.match(i, url):
                return
        # 获取权限信息
        permissions = request.session.get('permission')
        # 权限的校验
        for i in permissions:
            if re.match(r'^{}$'.format(i['permissions__url']), url):
                return
                # 拒绝请求
        return HttpResponse('没有访问权限,请联系管理员')
# settings.py中
# rbac 白名单
WHITE_LIST = [
    r'^/admin/',
    r'^/login/$',
    r'^/register/$',
]

# rabc 免认证
PASS_AUTH_LIST =[
    r'^/index/$'
]

五, 动态生成一级菜单

首先规范化RBAC:

在settings.py中配置
PERMISSION_SESSION_KEY  session中记录权限的key
MENU_SESSION_KEY        session中记录菜单信息的key
LOGIN_SESSION_KEY       session中记录登录状态的key

将相关template,static,服务等整理到rbac(app)内

model的更改:

# 权限表
class Permission(models.Model):
    url = models.CharField(max_length=108, verbose_name='权限')
    title = models.CharField(max_length=108, verbose_name='标题')
    is_menu = models.BooleanField(default=False, choices=((True, '是'), (False, '否')), verbose_name='是否目录')
    icon = models.CharField(max_length=64, verbose_name='图标', null=True, blank=True)

    def __str__(self):
        return self.title

session记录的更改:

# 查询当前用户的权限信息
# permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                'permissions__title',
                                                                                'permissions__is_menu',
                                                                                'permissions__icon',
                                                                                ).distinct()
# 权限的列表
permission_list = []
# 菜单的列表
menu_list = []

for i in permission:
    permission_list.append({
        'url': i['permissions__url']
    })
    if i.get('permissions__is_menu'):
        menu_list.append({
            'title': i['permissions__title'],
            'icon': i['permissions__icon'],
            'url': i['permissions__url']
        })
# 保存权限信息
request.session[settings.PERMISSION_SESSION_KEY] = permission_list
request.session[settings.LOGIN_SESSION_KEY] = True
# 保存菜单信息
request.session[settings.MENU_SESSION_KEY] = menu_list

自定义inclusion_tag:

// 插件 menu.html
<div class="static-menu">
    {% for menu in menu_list %}
        <a href="{{ menu.url }}" class="{{ menu.class }}">
            <span class="icon-wrap"><i class="fa {{ menu.icon }}"></i></span> {{ menu.title }}</a>
    {% endfor %}
</div>
from django import template
from django.conf import settings

register = template.Library()

@register.inclusion_tag('rbac/menu.html')
def menu(request):
    menu_list = request.session.get(settings.MENU_SESSION_KEY)
    url = request.path_info
    for menu in menu_list:
        if menu.get('url') == url:
            menu['class'] = 'active'
    return {'menu_list': request.session.get(settings.MENU_SESSION_KEY)}

六, 动态生成二级菜单

model的更改:

# 一级菜单表
class Menu(models.Model):
    title = models.CharField(max_length=108, verbose_name='一级菜单标题')
    icon = models.CharField(max_length=64, verbose_name='图标', null=True, blank=True)

    def __str__(self):
        return self.title


# 权限表(二级菜单)
class Permission(models.Model):
    '''
    menu_id: 有menu_id表示当前的权限是二级菜单
             没有menu_id表示当前的权限是普通权限
    '''
    url = models.CharField(max_length=108, verbose_name='权限')
    title = models.CharField(max_length=108, verbose_name='二级菜单标题')
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE, verbose_name='一级菜单', null=True, blank=True)

    def __str__(self):
        return self.title

session记录的更改:

# 查询当前用户的权限信息
# permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                'permissions__title',
                                                                                'permissions__menu__title',
                                                                                'permissions__menu__icon',
                                                                                'permissions__menu_id'
                                                                                ).distinct()
# 权限的列表
permission_list = []
# 菜单的字典
menu_dict = {}

for i in permission:
    permission_list.append({'url': i.get('permissions__url')})

    menu_id = i.get('permissions__menu_id')
    if menu_id:
        menu_dict.setdefault(menu_id, {
            'title': i['permissions__menu__title'],
            'icon': i['permissions__menu__icon'],
            'children': []
        })
        menu_dict[menu_id]['children'].append(
            {
                'title': i['permissions__title'],
                'url': i['permissions__url']
            }
        )
# 保存权限信息
request.session[settings.PERMISSION_SESSION_KEY] = permission_list
request.session[settings.LOGIN_SESSION_KEY] = True
# 保存菜单信息
request.session[settings.MENU_SESSION_KEY] = menu_dict

自定义inclusion_tag:

// 插件中 menu.html
<div class="multi-menu">
    {% for menu_first in menu_list %}
        <div class="item">
            <div class="title">
                <i class="fa {{ menu_first.icon }}"></i> {{ menu_first.title }}
            </div>
            <div class="body">
                {% for menu_second in menu_first.children %}
                    <a class="{{ menu_second.class }}" href="{{ menu_second.url }}">{{ menu_second.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>
# inclusion_tag
@register.inclusion_tag('rbac/menu.html')
def menu(request):
    menu_list = request.session.get(settings.MENU_SESSION_KEY).values()
    url = request.path_info
    for menu in menu_list:
        for i in menu.get('children'):
            if i.get('url') == url:
                i['class'] = 'active'
    return {'menu_list': menu_list}

七, 面包屑导航

model的更改:

# 一级菜单表
class Menu(models.Model):
    title = models.CharField(max_length=108, verbose_name='一级菜单标题')
    icon = models.CharField(max_length=64, verbose_name='图标', null=True, blank=True)
    weight = models.IntegerField(default=1, verbose_name='权重') # 用于一级菜单排序

    def __str__(self):
        return self.title


# 权限表(二级菜单)
class Permission(models.Model):
    url = models.CharField(max_length=108, verbose_name='权限')
    title = models.CharField(max_length=108, verbose_name='二级菜单标题')
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE, verbose_name='一级菜单', null=True, blank=True)
    parent = models.ForeignKey('self', on_delete=models.DO_NOTHING, verbose_name='父权限', null=True, blank=True)  # 用于区分二级权限和三级权限,生成面包屑导航

    def __str__(self):
        return self.title

session记录的更改:

    # 查询当前用户的权限信息
    # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
    permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                    'permissions__title',
                                                                                    'permissions__id',
                                                                                    'permissions__parent_id',
                                                                                    'permissions__menu__title',
                                                                                    'permissions__menu__icon',
                                                                                    'permissions__menu__weight',
                                                                                    'permissions__menu_id',
                                                                                    ).distinct()
    # 权限的字典
    permission_dict = {}
    # 菜单的字典
    menu_dict = {}

    for i in permission:
        permission_dict[i.get('permissions__id')] = {
            'url': i.get('permissions__url'),
            'title': i.get('permissions__title'),
            'id': i.get('permissions__id'),
            'parent_id': i.get('permissions__parent_id')

        }

        menu_id = i.get('permissions__menu_id')
        if menu_id:
            menu_dict.setdefault(menu_id, {
                'title': i['permissions__menu__title'],
                'icon': i['permissions__menu__icon'],
                'weight': i['permissions__menu__weight'],
                'children': []
            })
            menu_dict[menu_id]['children'].append(
                {
                    'title': i['permissions__title'],
                    'url': i['permissions__url'],
                    'id': i['permissions__id'],
                }
            )
    # 保存权限信息
    request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
    request.session[settings.LOGIN_SESSION_KEY] = True
    # 保存菜单信息
    request.session[settings.MENU_SESSION_KEY] = menu_dict
# 此时session记录信息数据格式
# 注意: 存入session中时经过json序列化,字典的key中的数字会转换为字符串
# 权限信息字典
{
	1: {
		'url': '/customer/list/',
		'title': '客户列表',
		'id': 1,
		'parent_id': None
	},
	2: {
		'url': '/customer/add/',
		'title': '添加客户',
		'id': 2,
		'parent_id': 1
	},
	3: {
		'url': '/customer/edit/(?P<cid>\\d+)/',
		'title': '编辑客户',
		'id': 3,
		'parent_id': 1
	},
	4: {
		'url': '/customer/del/(?P<cid>\\d+)/',
		'title': '删除客户',
		'id': 4,
		'parent_id': 1
	},
	5: {
		'url': '/payment/list/',
		'title': '缴费列表',
		'id': 5,
		'parent_id': None
	},
	6: {
		'url': '/payment/add/',
		'title': '添加缴费',
		'id': 6,
		'parent_id': 5
	},
	7: {
		'url': '/payment/edit/(?P<pid>\\d+)/',
		'title': '编辑缴费',
		'id': 7,
		'parent_id': 5
	},
	8: {
		'url': '/payment/del/(?P<pid>\\d+)/',
		'title': '删除缴费',
		'id': 8,
		'parent_id': 5
	}
}

# 菜单信息字典
{
	1: {
		'title': '客户管理',
		'icon': 'fa-address-book',
		'weight': 10,
		'children': [{
			'title': '客户列表',
			'url': '/customer/list/',
			'id': 1
		}]
	},
	2: {
		'title': '财务管理',
		'icon': 'fa-money',
		'weight': 1,
		'children': [{
			'title': '缴费列表',
			'url': '/payment/list/',
			'id': 5
		}]
	}
}

中间件的更改:

class Rbac(MiddlewareMixin):

    def process_request(self, request):
        # 获取当前访问的地址
        url = request.path_info
        # 初始化current_menu_id
        request.current_menu_id = None
        # 初始化导航列表
        request.breadcrumb_list = [
            {'title': '首页', 'url': '/index/'}
        ]
        # 白名单
        for i in settings.WHITE_LIST:
            if re.match(i, url):
                return
        # 登陆状态的校验
        is_login = request.session.get(settings.LOGIN_SESSION_KEY)
        if not is_login:
            return redirect('login')
        # 免认证校验
        for i in settings.PASS_AUTH_LIST:
            if re.match(i, url):
                return
        # 获取权限信息
        permissions = request.session.get(settings.PERMISSION_SESSION_KEY)
        # 权限的校验
        for i in permissions.values():
            # i 权限  父权限  子权限
            if re.match(fr'^{i["url"]}$', url):
                menu_id = i.get('parent_id')
                if not menu_id:
                    # 当前访问的权限是父权限(二级菜单)
                    menu_id = i.get('id')
                    request.breadcrumb_list.append({
                        'title': i['title'],
                        'url': i['url']
                    })
                else:
                    # 当前访问的权限是子权限
                    parent_permission = permissions[str(menu_id)]
                    request.breadcrumb_list.append({
                        'title': parent_permission['title'],
                        'url': parent_permission['url'],
                    })
                    request.breadcrumb_list.append({
                        'title': i['title'],
                        'url': i['url'],
                    })
                request.current_menu_id = menu_id
                return
                # 拒绝请求
        return render(request, 'rbac/403.html')

自定义inclusion_tag:

@register.inclusion_tag('rbac/menu.html')
def menu(request):
    menu_list = request.session.get(settings.MENU_SESSION_KEY).values()
    od_menu_list = sorted(menu_list, key=lambda x: x['weight'], reverse=True)
    for menu in od_menu_list:
        menu['class'] = 'hidden'
        for i in menu.get('children'):
            if i.get('id') == request.current_menu_id:
                i['class'] = 'active'
                menu['class'] = ''
                break
    return {'menu_list': od_menu_list}
// 插件  menu.html
<div class="multi-menu">
    {% for menu_first in menu_list %}
        <div class="item">
            <div class="title">
                <i class="fa {{ menu_first.icon }}"></i> {{ menu_first.title }}
            </div>
            <div class="body {{ menu_first.class }}">
                {% for menu_second in menu_first.children %}
                    <a class="{{ menu_second.class }}" href="{{ menu_second.url }}">{{ menu_second.title }}</a>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
</div>
--------------------------------------------------------------
// breadcrumb.html
<ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;">
    {% for breadcrumb in breadcrumb_list %}
        {% if forloop.last %}
            <li class="active">{{ breadcrumb.title }}</li>
        {% else %}
            <li><a href="{{ breadcrumb.url }}">{{ breadcrumb.title }}</a></li>
        {% endif %}
    {% endfor %}
</ol>

八, 权限控制到按钮级别

model的更改:

# 权限表(二级菜单)
class Permission(models.Model):
    '''
    name: 权限控制到按钮级别,判断是否有这个权限
    '''
    url = models.CharField(max_length=108, verbose_name='权限')
    name = models.CharField(max_length=108, verbose_name='url别名', unique=True)
    title = models.CharField(max_length=108, verbose_name='二级菜单标题')
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE, verbose_name='一级菜单', null=True, blank=True)
    parent = models.ForeignKey('self', on_delete=models.DO_NOTHING, verbose_name='父权限', null=True, blank=True)

    def __str__(self):
        return self.title

session记录的更改:

# 查询当前用户的权限信息
    # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
    permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                    'permissions__title',
                                                                                    'permissions__id',
                                                                                    'permissions__name',
                                                                                    'permissions__parent_id',
                                                                                    'permissions__parent__name',
                                                                                    'permissions__menu__title',
                                                                                    'permissions__menu__icon',
                                                                                    'permissions__menu__weight',
                                                                                    'permissions__menu_id',
                                                                                    ).distinct()
    # 权限的字典
    permission_dict = {}
    # 菜单的字典
    menu_dict = {}
    for i in permission:
        permission_dict[i.get('permissions__name')] = {
            'url': i.get('permissions__url'),
            'title': i.get('permissions__title'),
            'id': i.get('permissions__id'),
            'parent_id': i.get('permissions__parent_id'),
            'parent_name': i.get('permissions__parent__name'),
        }
        menu_id = i.get('permissions__menu_id')
        if menu_id:
            menu_dict.setdefault(menu_id, {
                'title': i['permissions__menu__title'],
                'icon': i['permissions__menu__icon'],
                'weight': i['permissions__menu__weight'],
                'children': []
            })
            menu_dict[menu_id]['children'].append(
                {
                    'title': i['permissions__title'],
                    'url': i['permissions__url'],
                    'id': i['permissions__id'],
                }
            )
    # 保存权限信息
    request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
    request.session[settings.LOGIN_SESSION_KEY] = True
    # 保存菜单信息
    request.session[settings.MENU_SESSION_KEY] = menu_dict

中间件:

# 获取权限信息
permissions = request.session.get(settings.PERMISSION_SESSION_KEY)
# 权限的校验

for i in permissions.values():
    # i权限  父权限  子权限
    if re.match(fr'^{i["url"]}$', url):
        menu_id = i.get('parent_id')
        if not menu_id:
            # 当前访问的权限是父权限(二级菜单)
            menu_id = i.get('id')
            request.breadcrumb_list.append({
                'title': i['title'],
                'url': i['url']
            })
        else:
            # 当前访问的权限是子权限
            parent_name = i.get('parent_name')
            parent_permission = permissions[parent_name]
            request.breadcrumb_list.append({
                'title': parent_permission['title'],
                'url': parent_permission['url'],
            })
            request.breadcrumb_list.append({
                'title': i['title'],
                'url': i['url'],
            })
        request.current_menu_id = menu_id
        return
        # 拒绝请求
return render(request, 'rbac/403.html')

自定义tags:

@register.inclusion_tag('rbac/menu.html')
def menu(request):
    menu_list = request.session.get(settings.MENU_SESSION_KEY).values()
    od_menu_list = sorted(menu_list, key=lambda x: x['weight'], reverse=True)
    for menu in od_menu_list:
        menu['class'] = 'hidden'
        for i in menu.get('children'):
            if i.get('id') == request.current_menu_id:
                i['class'] = 'active'
                menu['class'] = ''
                break
    return {'menu_list': od_menu_list}


@register.inclusion_tag('rbac/breadcrumb.html')
def breadcrumb(request):
    return {
        'breadcrumb_list': request.breadcrumb_list
    }


@register.filter
def has_permission(request, name):
    permission = request.session.get(settings.PERMISSION_SESSION_KEY)
    if name in permission:
        return True

模板中使用:

{% if request|has_permission:'customer_add' %}
    <a class="btn btn-default" href="{% url 'customer_add' %}">
        <i class="fa fa-plus-square" aria-hidden="true"></i> 添加客户
    </a>
{% endif %}

九, 权限管理

routes.py中

from django.conf import settings
from django.utils.module_loading import import_string
from django.urls import RegexURLResolver, RegexURLPattern
from collections import OrderedDict


def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict):

    for item in urlpatterns:
        if isinstance(item, RegexURLResolver):
            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

            " None   /^  "
            recursion_urls(namespace, pre_url + item.regex.pattern, item.url_patterns, url_ordered_dict)
        else:

            if pre_namespace:
                name = "%s:%s" % (pre_namespace, item.name,)
            else:
                name = item.name
            if not item.name:
                raise Exception('URL路由中必须设置name属性')
            """
            /^^login/$    /login/ 
            """
            url = pre_url + item._regex
            url_ordered_dict[name] = {'name': name, 'url': url.replace('^', '').replace('$', '')}


def get_all_url_dict(ignore_namespace_list=None):
    """
    获取路由中
    :return:
    """
    ignore_list = ignore_namespace_list or []
    url_ordered_dict = OrderedDict()

    md = import_string(settings.ROOT_URLCONF)  # 根据路径的字符串 导入模块
    urlpatterns = []
    
    for item in md.urlpatterns:
        if isinstance(item, RegexURLResolver) and item.namespace in ignore_list:
            continue
        urlpatterns.append(item)
    recursion_urls(None, "/", urlpatterns, url_ordered_dict)
    return url_ordered_dict

views.py

from django.shortcuts import render, redirect, reverse, HttpResponse
from django.views import View
from rbac import models
from django.db.models import Q
from rbac.forms import RoleForm
from rbac.forms import MenuForm
from rbac.forms import PermissionForm
from rbac.forms import MultiPermissionForm
from django.forms import modelformset_factory, formset_factory
from rbac.service.routes import get_all_url_dict


# 展示角色
class RoleList(View):

    def get(self, request):
        all_role = models.Role.objects.all()
        return render(request, 'rbac/role_list.html', {
            'all_role': all_role
        })


# 新增编辑角色
class RoleChange(View):
    def get(self, request, role_id=None, *args, **kwargs):
        role_obj = models.Role.objects.filter(pk=role_id).first()
        form_obj = RoleForm(instance=role_obj)
        return render(request, 'rbac/forms.html', {
            'form_obj': form_obj,
        })

    def post(self, request, role_id=None, *args, **kwargs):
        role_obj = models.Role.objects.filter(pk=role_id).first()
        form_obj = RoleForm(instance=role_obj, data=request.POST)
        if form_obj.is_valid():
            form_obj.save()
            return redirect('rbac:role_list')
        return render(request, 'rbac/forms.html', {
            'form_obj': form_obj,
        })


# 展示权限信息
class MenuList(View):
    def get(self, request):
        mid = request.GET.get('mid')
        if not mid:
            all_permission = models.Permission.objects.all()
        else:
            all_permission = models.Permission.objects.filter(Q(menu_id=mid) | Q(parent__menu_id=mid))
        # all_permission = all_permission.values('id', 'title', 'name', 'url', 'menu_id', 'menu__title', 'parent_id')
        permission_dict = {}
        for i in all_permission:
            menu_id = i.menu_id
            id = i.pk
            if menu_id:
                i.children = []
                permission_dict[id] = i
        for i in all_permission:
            parent_id = i.parent_id
            if parent_id:
                permission_dict[parent_id].children.append(i)
        all_menu = models.Menu.objects.all()
        return render(request, 'rbac/menu_list.html', {
            'all_menu': all_menu,
            'all_permission': permission_dict.values(),
            'mid': mid,
        })


# 新增编辑菜单
class MenuChange(View):
    def get(self, request, menu_id=None, *args, **kwargs):
        menu_obj = models.Menu.objects.filter(pk=menu_id).first()
        form_obj = MenuForm(instance=menu_obj)
        return render(request, 'rbac/menu_form.html', {
            'form_obj': form_obj,
        })

    def post(self, request, menu_id=None, *args, **kwargs):
        menu_obj = models.Menu.objects.filter(pk=menu_id).first()
        form_obj = MenuForm(instance=menu_obj, data=request.POST)
        if form_obj.is_valid():
            form_obj.save()
            return redirect('rbac:menu_list')
        return render(request, 'rbac/menu_form.html', {
            'form_obj': form_obj,
        })


# 新增编辑权限
class PermissionChange(View):
    def get(self, request, permission_id=None, *args, **kwargs):
        permission_obj = models.Permission.objects.filter(pk=permission_id).first()
        form_obj = PermissionForm(instance=permission_obj)
        return render(request, 'rbac/menu_form.html', {
            'form_obj': form_obj,
        })

    def post(self, request, permission_id=None, *args, **kwargs):
        permission_obj = models.Permission.objects.filter(pk=permission_id).first()
        form_obj = PermissionForm(instance=permission_obj, data=request.POST)
        if form_obj.is_valid():
            form_obj.save()
            return redirect('rbac:menu_list')
        return render(request, 'rbac/forms.html', {
            'form_obj': form_obj,
        })


# 删除
class Delete(View):
    def get(self, request, table, pk):
        model = getattr(models, table.capitalize())
        if not model:
            return HttpResponse('非法操作')
        obj = model.objects.filter(pk=pk).first()
        if not obj:
            return HttpResponse('非法操作')
        obj.delete()
        return redirect(request.META['HTTP_REFERER'])


def multi_permissions(request):
    """
    批量操作权限
    :param request:
    :return:
    """
    post_type = request.GET.get('type')
    # 编辑  删除
    FormSet = modelformset_factory(models.Permission, MultiPermissionForm, extra=0)
    # 新增
    AddFormSet = formset_factory(MultiPermissionForm, extra=0)
    # 数据库所有的权限
    permissions = models.Permission.objects.all()
    # 路由系统的所有的url 权限
    router_dict = get_all_url_dict(ignore_namespace_list=['admin'])

    # 数据库权限的name的集合
    permissions_name_set = set([i.name for i in permissions])
    # 路由系统中权限的name的集合
    router_name_set = set(router_dict.keys())

    add_name_set = router_name_set - permissions_name_set
    add_formset = AddFormSet(initial=[row for name, row in router_dict.items() if name in add_name_set])

    if request.method == 'POST' and post_type == 'add':
        add_formset = AddFormSet(request.POST)
        if add_formset.is_valid():
            permission_obj_list = [models.Permission(**i) for i in add_formset.cleaned_data]
            query_list = models.Permission.objects.bulk_create(permission_obj_list)
            add_formset = AddFormSet()
            for i in query_list:
                permissions_name_set.add(i.name)

    del_name_set = permissions_name_set - router_name_set
    del_formset = FormSet(queryset=models.Permission.objects.filter(name__in=del_name_set))

    update_name_set = permissions_name_set & router_name_set
    update_formset = FormSet(queryset=models.Permission.objects.filter(name__in=update_name_set))

    if request.method == 'POST' and post_type == 'update':
        update_formset = FormSet(request.POST)
        if update_formset.is_valid():
            update_formset.save()
            update_formset = FormSet(queryset=models.Permission.objects.filter(name__in=update_name_set))

    return render(
        request,
        'rbac/multi_permissions.html',
        {
            'del_formset': del_formset,
            'update_formset': update_formset,
            'add_formset': add_formset,
        }
    )


def distribute_permissions(request):
    """
    分配权限
    :param request:
    :return:
    """
    uid = request.GET.get('uid')
    rid = request.GET.get('rid')

    if request.method == 'POST' and request.POST.get('postType') == 'role':
        user = models.UserInfo.objects.filter(id=uid).first()
        if not user:
            return HttpResponse('用户不存在')
        user.roles.set(request.POST.getlist('roles'))

    if request.method == 'POST' and request.POST.get('postType') == 'permission' and rid:
        role = models.Role.objects.filter(id=rid).first()
        if not role:
            return HttpResponse('角色不存在')
        role.permissions.set(request.POST.getlist('permissions'))

    # 所有的用户
    user_list = models.UserInfo.objects.all()
    # 用户所拥有的角色 id
    user_has_roles = models.UserInfo.objects.filter(id=uid).values('id', 'roles')

    # 用户所拥有的角色id   {角色的id:None }
    user_has_roles_dict = {item['roles']: None for item in user_has_roles}
    # 所有的角色
    role_list = models.Role.objects.all()

    if rid:
        role_has_permissions = models.Role.objects.filter(id=rid, permissions__id__isnull=False).values('id',
                                                                                                        'permissions')
    elif uid and not rid:
        user = models.UserInfo.objects.filter(id=uid).first()
        if not user:
            return HttpResponse('用户不存在')
        role_has_permissions = user.roles.filter(permissions__id__isnull=False).values('id', 'permissions')
    else:
        role_has_permissions = []

    # 用户 或者 角色所拥有的权限
    role_has_permissions_dict = {item['permissions']: None for item in role_has_permissions}

    all_menu_list = []

    queryset = models.Menu.objects.values('id', 'title')  # [ { id  title } ]
    menu_dict = {}

    for item in queryset:
        # { id  title  children:[]  }
        item['children'] = []
        menu_dict[item['id']] = item
        all_menu_list.append(item)

    other = {'id': None, 'title': '其他', 'children': []}
    all_menu_list.append(other)
    menu_dict[None] = other

    root_permission = models.Permission.objects.filter(menu__isnull=False).values('id', 'title', 'menu_id')
    root_permission_dict = {}
    for per in root_permission:
        # { id  title menu_id   'children':[] }
        per['children'] = []
        nid = per['id']
        menu_id = per['menu_id']
        root_permission_dict[nid] = per
        menu_dict[menu_id]['children'].append(per)

    node_permission = models.Permission.objects.filter(menu__isnull=True).values('id', 'title', 'parent_id')

    for per in node_permission:
        # {  id  title parent_id  }
        pid = per['parent_id']
        if not pid:
            menu_dict[None]['children'].append(per)
            continue
        root_permission_dict[pid]['children'].append(per)

    return render(
        request,
        'rbac/distribute_permissions.html',
        {
            'user_list': user_list,  # 所有的用户
            'role_list': role_list,  # 所有的角色
            'user_has_roles_dict': user_has_roles_dict,  # 用户所拥有的角色
            'role_has_permissions_dict': role_has_permissions_dict,  # 角色拥有的权限
            'all_menu_list': all_menu_list,  # 菜单列表
            'uid': uid,
            'rid': rid
        }
    )

标签:__,管理,url,menu,request,Django,权限,id,permissions
From: https://www.cnblogs.com/HeroZhang/p/18096057

相关文章

  • 中电金信:打好智能风控四张牌 筑牢财务公司风险管理防护网
    ​2021年,国务院印发《“十四五”数字经济发展规划的通知》,为我国金融行业数字化建设指明了目标和方向,对金融企业数字化转型提出了更高要求。企业集团财务公司作为服务于大型企业改革的金融配套政策的机构,30多年来立足于产融结合,扎根实业、服务企业集团,实现了快速发展。在新形势下,......
  • 【附源码】Node.js毕业设计高校迎新管理系统(Express)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:随着信息技术的飞速发展,高校迎新工作也日益依赖于数字化和信息化手段。传统的手工操作方式已经无法满足现代高校迎新工作的高效率、高质量要求。因此,构建一......
  • 【附源码】Node.js毕业设计高校疫情期间学生日常管理系统(Express)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:随着COVID-19疫情的爆发,全球范围内的教育行业遭受了巨大的冲击。为了防止病毒的传播,许多国家和地区都采取了封锁措施,学校被迫关闭,线下教学活动无法正常进行......
  • 【附源码】Node.js毕业设计高校疫情管理系统(Express)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:随着科技的不断发展和互联网技术的普及,信息化管理系统在各个领域的应用越来越广泛。特别是在新冠疫情期间,高校疫情管理成为了一个重要的课题。为了有效地控......
  • 关于SQL Server数据库中的用户权限和角色管理
    简介在SQLServer数据库系统中,管理用户权限和角色对于确保数据安全、完整性和可访问性至关重要。在本文中,我们将探讨在SQLServer数据库中创建用户、分配权限和管理角色的过程。我们将涵盖基本概念,并提供带有SQL代码片段的实际示例。引言用户管理涉及创建用户帐户、分配适当的......
  • 工业园区聚集地数字孪生:打造智能管理与发展的新引擎
    随着科技的飞速发展,数字化浪潮席卷全球,各行各业都迎来了前所未有的变革。在这个数字化时代,工业园区作为经济发展的重要引擎,正积极拥抱新技术,以数字孪生系统为引领,开启一场全新的工业革命。 数字孪生是指通过数字技术对实体世界进行精准映射,实现虚实结合的智能化管理。在工业园......
  • 青年人格测验,管理岗和管培生的招聘测评
    青年人格测验是由美国心理学家高夫提出,并逐渐完善的一种性格测试工具。在青年人格测验中,人的人格特质被分为许多个维度,不同的维度,都能对我们健全自身性格,了解自己,起着至关重要的作用。高夫曾是mmpi量表的编撰者之一,mmpi量表不用说了,在心理测评领域当之无愧的老大哥。而青年人......
  • nvm: node管理工具
    nvm官网下载地址 https://nvm.uihtm.com/从官网安装后确认nvm,打开cmd,输入命令nvm,显示以下,说明安装成功nvm常用命令(1)nvm-v:查看nvm版本(2)nvmlist:显示已经安装的版本(3)nvmlistavailable:显示可下载版本的部分列表(4)nvmuse版本号:使用指定node版本(nvmuse18.7.0)(5)nvm......
  • java毕业设计房产销售管理小程序[附源码]
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:在当今数字化时代,房产销售行业正经历着前所未有的变革。随着信息技术的飞速发展,传统的房产销售模式已经无法满足市场的需求。购房者越来越倾向于通过网络......
  • 【薪酬设计】某纺织企业薪酬体系设计管理咨询项目纪实
    作为一家传统型的纺织企业,我公司在基层员工的薪酬管理方面问题重重。由于缺乏专业的人力资源知识和管理实践,我们开始寻求人力资源专家:华恒智信的帮助。华恒智信专家团队对我公司进行了为期3周的认真细致、深入缜密的调研和访谈,做出了具有较高专业性的诊断报告,提出了专业的分析......