【Django项目开发】角色管理模块的开发(八)

导读:本篇文章讲解 【Django项目开发】角色管理模块的开发(八),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

在这里插入图片描述


一、序列化器设计

1、嵌套的序列化器设计

需求:查询某个角色下的信息,包括该角色下的权限信息

a、自定义的序列化器类实际上也Field子类
b、所以自定义的序列化器类可以作为另外一个序列化器中的字段来使用

RolesModel和PermissionsModel两个模型类的关联字段为permissions
序列化中通过permissions字段接收
permissions=PermissionsSerializer(many=True,read_only=True):多对多的关联关系采用permissions,
many=True:因为是多对多的关系,数据可能有多条
如果是一对多的关联关系:permissions_set,

permission_serializer.py

class PermissionsSerializer(ModelSerializer):

    class Meta:
        model=PermissionsModel
        fields='__all__'

2、普通的序列化类支持:新增、修改角色名、删除、查询

roles_serializer.py

class BaseRolesSerializer(ModelSerializer):
    """
    普通的序列化类,支持:新增,修改角色名,删除、查询
    """
    permissions=PermissionsSerializer(many=True,read_only=True)
    class Meta:
        model=RolesModel
        fields='__all__'

3、用于给某一个角色批量授权的序列化

class RolesPartialSerializer(ModelSerializer):
    """
    用于给某一个角色批量授权的序列化
    """

    class Meta:
        model = RolesModel
        fields = ['id','permissions']

4、用于给某一个角色单一授权,包括取消单一授权

class RoleSetPermissionSerializer(Serializer):
    """
    用于给某一个角色单一授权,包括取消单一授权
    """
    #角色id
    role_id=IntegerField(write_only=True,required=True)
    #权限id
    permission_id=IntegerField(write_only=True,required=True)
    #是否授予权限还是取消;是(True);取消(False)
    is_create=BooleanField(write_only=True,required=True)

二、视图类设计

1、包含的接口有哪些

角色的增加:create
查询单个角色:retrieve
查询所有的角色:list
修改角色,仅仅修改角色的名字(属性):update
局部修改角色(角色的批量授权):partial_update
删除角色:destroy
批量删除角色:multiple_delete
给单个角色,单一授权:set_permission_to_role

上面的接口中,其中multiple_delete已经自定义抽象化,直接继承就行;
而set_permission_to_role需要在视图中实现

2、set_permission_to_role方法的实现

2.1、ser.is_valid()

ser.is_valid():作用是:对前端传递过来的数据进行校验;如果校验通过的,通过ser.validated_data可以获取到校验通过后的数据,为字典类型;
如果校验不通过,可以通过ser.errors属性获取错误信息,返回字典,包含了字段和字段的错误;如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。

2.2、授权和取消授权

role.permissions.add(permission)
role.permissions.remove(permission)

2.3、特别注意:

判断该权限对应的父菜单权限是否被授予,如果没有授权,需要把父菜单的权限也加进去

	@action(methods=['post'],detail=False)
    def set_permission_to_role(self,request,*args,**kwargs):
        ser=RoleSetPermissionSerializer(data=request.data)
        if ser.is_valid():
            #查询当前角色
            role=RolesModel.objects.get(id=ser.validated_data.get('role_id'))
            print('role:',role)
            #查询权限
            permission=PermissionsModel.objects.get(id=ser.validated_data.get('permission_id'))
            print('permission:',permission)
            if ser.validated_data.get('is_create'):
                #todo 判断该权限对应的父菜单权限是否被授予
                #todo 得到该权限对应的接口菜单  的父菜单
                parent_ids=MenuModel.objects.filter(id=permission.menu.id).values_list('parent',flat=True).all()
                if parent_ids:
                    parent_permission=PermissionsModel.objects.get(menu_id=parent_ids[0])
                    role.permissions.add(parent_permission)     #todo 把父菜单的权限也加进去
                print('role.permissions:',role.permissions)
                role.permissions.add(permission)    #把当前的权限授予当前的角色
                print('role.permissions:', role.permissions)

            else:#取消授权
                role.permissions.remove(permission)     #删除当前角色的当前权限
            result_ser=BaseRolesSerializer(instance=role)
            return Response(data=result_ser.data)

3、特别注意

角色数据库中有一个固定的角色:admin。这个角色代表所有权限,不能删除

需要重写destroy方法和multiple_delete方法

    #重写destroy函数,因为admin角色不能删除
    def destroy(self, request, *args, **kwargs):
        if self.get_object().name=='admin':
            return Response(data={'error':'admin角色不能删除'},status=status.HTTP_400_BAD_REQUEST)
        return super().destroy(request, *args, **kwargs)

    del_ids = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        "ids": openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择那些需要删除的ID(主键)")
    })

    @swagger_auto_schema(method='delete', request_body=del_ids, operation_description="批量删除菜单")  # 接口注释
    @action(methods=['delete'],detail=False)
    def multiple_delete(self,request,*args,**kwargs):
        delete_ids=request.data.get('ids')
        try:
            admin=RolesModel.objects.get(name='admin')
            if isinstance(delete_ids,list):
                if admin.id in delete_ids:
                    return Response(data={'error': 'admin角色不能删除'}, status=status.HTTP_400_BAD_REQUEST)
        except RolesModel.DoesNotExist as ex:
            pass

        return super().multiple_delete(request,*args,**kwargs)

4、完整代码

from rest_framework import viewsets
from erp_project.utils.base_views import MultipleDestroyMixin
from erp_system.models import RolesModel,PermissionsModel,MenuModel
from erp_system.serializer.role_serializer import RolesPartialSerializer,RoleSetPermissionSerializer,BaseRolesSerializer
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
from drf_yasg2 import openapi
from drf_yasg2.utils import swagger_auto_schema
from rest_framework.permissions import IsAuthenticated

#角色数据库中有一个固定的角色:admin。这个角色代表所有权限,不能删除
class RolesView(viewsets.ModelViewSet,MultipleDestroyMixin):
    """
        create:
        角色--新增,

        角色新增,status:201(成功),return:新增角色信息

        list:
        查询所有的角色

        update:
        修改角色,仅仅修改角色的名字(属性)

        destroy:
        角色--删除 单个角色

        角色删除,status:204,return:None

        partial_update:
        局部修改角色(角色的批量授权),只能针对某一个角色一次性授权,之前的授权会被覆盖

        multiple_delete:
        角色--批量删除

        角色删除,status:204,return:None

        set_permission_to_role:
        给单个角色,单一授权。一次只能授予角色一个permission,也可以取消一个permission

        """
    queryset=RolesModel.objects.all()
    serializer_class = BaseRolesSerializer
    permission_classes = [IsAuthenticated]

    def get_serializer_class(self):
        if self.action=='partial_update':
            return RolesPartialSerializer
        elif self.action=='set_permission_to_role':
            return RoleSetPermissionSerializer
        else:
            return BaseRolesSerializer

    @action(methods=['post'],detail=False)
    def set_permission_to_role(self,request,*args,**kwargs):
        ser=RoleSetPermissionSerializer(data=request.data)
        if ser.is_valid():
            #查询当前角色
            role=RolesModel.objects.get(id=ser.validated_data.get('role_id'))
            print('role:',role)
            #查询权限
            permission=PermissionsModel.objects.get(id=ser.validated_data.get('permission_id'))
            print('permission:',permission)
            if ser.validated_data.get('is_create'):
                #todo 判断改权限对应的父菜单权限是否被授予
                #todo 得到该权限对应的接口菜单  的父菜单
                parent_ids=MenuModel.objects.filter(id=permission.menu.id).values_list('parent',flat=True).all()
                if parent_ids:
                    parent_permission=PermissionsModel.objects.get(menu_id=parent_ids[0])
                    role.permissions.add(parent_permission)     #todo 把父菜单的权限也加进去
                print('role.permissions:',role.permissions)
                role.permissions.add(permission)    #把当前的权限授予当前的角色
                print('role.permissions:', role.permissions)

            else:#取消授权
                role.permissions.remove(permission)     #删除当前角色的当前权限
            result_ser=BaseRolesSerializer(instance=role)
            return Response(data=result_ser.data)

    #重写destroy函数,因为admin角色不能删除
    def destroy(self, request, *args, **kwargs):
        if self.get_object().name=='admin':
            return Response(data={'error':'admin角色不能删除'},status=status.HTTP_400_BAD_REQUEST)
        return super().destroy(request, *args, **kwargs)

    del_ids = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        "ids": openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择那些需要删除的ID(主键)")
    })

    @swagger_auto_schema(method='delete', request_body=del_ids, operation_description="批量删除菜单")  # 接口注释
    @action(methods=['delete'],detail=False)
    def multiple_delete(self,request,*args,**kwargs):
        delete_ids=request.data.get('ids')
        try:
            admin=RolesModel.objects.get(name='admin')
            if isinstance(delete_ids,list):
                if admin.id in delete_ids:
                    return Response(data={'error': 'admin角色不能删除'}, status=status.HTTP_400_BAD_REQUEST)
        except RolesModel.DoesNotExist as ex:
            pass

        return super().multiple_delete(request,*args,**kwargs)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/73915.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!