zoukankan      html  css  js  c++  java
  • day01

    day 01

    models文件

      用户和角色多对多的原因在于,可能存在临时项目。某个用户除了正常角色,还有可能是安全小组类似的这样的角色。

    from django.db import models
    
    # Create your models here.
    class UserInfo(models.Model):
        name=models.CharField(max_length=32,verbose_name='用户名')
        pwd=models.CharField(max_length=32,verbose_name='密码')
        email=models.CharField(max_length=32,verbose_name='邮箱')
        roles=models.ManyToManyField(to='Role')
        def __str__(self):
            return self.name
    
    class Role(models.Model):
        name=models.CharField(max_length=32,verbose_name='角色名')
        permissions=models.ManyToManyField(to='Permission')
        def __str__(self):
            return self.name
    
    
    
    class Permission(models.Model):
        name=models.CharField(max_length=32,verbose_name='权限名')
        url=models.CharField(max_length=200,verbose_name='网址',default=None)
        def __str__(self):
            return self.name

    PS:考虑到有可能有这种情况。新增了一个role,但是暂时没有权限。so,将上述代码修正如下。 roles=.......,blank=True)

    from django.db import models
    
    # Create your models here.
    class UserInfo(models.Model):
        name=models.CharField(max_length=32,verbose_name='用户名')
        pwd=models.CharField(max_length=32,verbose_name='密码')
        email=models.CharField(max_length=32,verbose_name='邮箱')
        roles=models.ManyToManyField(to='Role')
        def __str__(self):
            return self.name
    
    class Role(models.Model):
        name=models.CharField(max_length=32,verbose_name='角色名')
        permissions=models.ManyToManyField(to='Permission',blank=True)
        def __str__(self):
            return self.name
    
    
    
    class Permission(models.Model):
        name=models.CharField(max_length=32,verbose_name='权限名')
        url=models.CharField(max_length=200,verbose_name='网址',default=None)
        def __str__(self):
            return self.name

      

    用户 --->角色---->权限,正向查询比价方便。所以,多对多的关系,如上图所示。

    views文件

    Func1:

    用户登录后,后台视图函数通过request.POST.get方法 拿到前端传来的数据,对数据库内的数据进行过滤。

    在此之前,把models里的所有模型导入到views文件中。

    from rbac.models import *
    
    def login(request):
        if request.method=='POST':
            username=request.POST.get('username')
            password=request.POST.get('password')
            user=UserInfo.objects.filter(name=username,pwd=password).first()

      

      

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Func2:

    如果验证通过,查询此人的权限。UserInfo -->Role -->  Permissions

    补充:

    values

     

    values(*fields)

    返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。

    每个字典表示一个对象,键对应于模型对象的属性名称

            if user:
                permission_list1=user.roles.all()
                for i in permission_list1:
                    print(i,type(i))
                permission_list4 = user.roles.all().values()
                for i in permission_list4:
                    print(i, type(i))
                permission_list2 = user.roles.all().values('name')
                for i in permission_list2:
                    print(i,type(i))
                permission_list3=user.roles.all().values('name','permissions__name','permissions__url')
    
                print(permission_list1,type(permission_list1))
                print(permission_list2,type(permission_list2))
                print(permission_list3,type(permission_list3))
                print(permission_list4,type(permission_list4))

    输出:

    材料员 <class 'rbac.models.Role'>
    {'id': 4, 'name': '材料员'} <class 'dict'>
    {'name': '材料员'} <class 'dict'>
    <QuerySet [<Role: 材料员>]> <class 'django.db.models.query.QuerySet'>
    <QuerySet [{'name': '材料员'}]> <class 'django.db.models.query.QuerySet'>
    <QuerySet [{'name': '材料员', 'permissions__name': '查询订单', 'permissions__url': '/order/select/'}, {'name': '材料员', 'permissions__name': '查询用户', 'permissions__url': '/user/select/'}]> <class 'django.db.models.query.QuerySet'>
    <QuerySet [{'id': 4, 'name': '材料员'}]> <class 'django.db.models.query.QuerySet'>
    {'name': '材料员', 'permissions__name': '查询订单', 'permissions__url': '/order/select/'}
    {'name': '材料员', 'permissions__name': '查询用户', 'permissions__url': '/user/select/'}

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

      Django 提供一种强大而又直观的方式来“处理”查询中的关联关系,它在后台自动帮你处理JOIN。 若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段.

    from rbac.models import *
    
    def login(request):
        if request.method=='POST':
            username=request.POST.get('username')
            password=request.POST.get('password')
            user=UserInfo.objects.filter(name=username,pwd=password).first()
            # print(user,type(user))
            if user:
                permission_list=user.roles.all().values('name','permissions__name','permissions__url')
                for item in permission_list:
                    print(item)
                return HttpResponse('登录成功!')
    
        return render(request,'login.html')

    输出:

    {'name': '材料员', 'permissions__name': '查询订单', 'permissions__url': '/order/select/'}
    {'name': '材料员', 'permissions__name': '查询用户', 'permissions__url': '/user/select/'}

    改进:

    可能一个人都多个角色,角色拥有的权限可能有交集。基于这一点考虑,对以上代码进行修正。去掉values()内的name字段。因为这个name字段是roles对象的name,在这里并没有用处,我们需要的是 权限名。

    from rbac.models import *
    
    def login(request):
        if request.method=='POST':
            username=request.POST.get('username')
            password=request.POST.get('password')
            user=UserInfo.objects.filter(name=username,pwd=password).first()
            # print(user,type(user))
            if user:
                permission_list=user.roles.all().values('permissions__name','permissions__url').distinct()
                for item in permission_list:
                    print(item)
                return HttpResponse('登录成功!')
    
        return render(request,'login.html')

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    实现用户登录成功后,将其权限加入到session中。请求 不同页面,根据用户权限不同,在页面中显示不同的结果。

    为什么加入session中,当未登录的用户 想要查看/user/select/,这是肯定不行的。通过session判断当前用户的权限。同时,减轻了数据库的压力,不必一次一次的查询数据库。

    若是用户的权限改了呢?很简单,提示用户重新登录。这是普遍的做法。

    def userselect(request):
        '''
        根据有无权限,
        显示所有的用户信息
        :param request:
        :return:
        '''
        if request.session.get('url_list'):
            url_list=request.session.get('url_list')
            flag = False
            for url in url_list:
                if re.match(url,request.path_info):
                    flag=True
                    break
            if flag:
                users=UserInfo.objects.all()
                return render(request,'userselect.html',{'users':users})
            else:
                return HttpResponse('无权访问')
        else:
            return redirect('/login/')

    其它的也顺理成章喽

      

    def orderselect(request):
        '''
            根据有无权限,
            显示所有的订单信息
            :param request:
            :return:
            '''
        if request.session.get('url_list'):
            url_list = request.session.get('url_list')
            flag = False
            for url in url_list:
                if re.match(url, request.path_info):
                    flag = True
                    break
            if flag:
                orders= Order.objects.all()
                return render(request, 'orderselect.html', {'orders':orders})
            else:
                return HttpResponse('无权访问')
        else:
            return redirect('/login/')

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    上一步有没有优化的地方呢?

    感受到了

    在rbac这个项目中,所有的视图函数,都需要先判定下当前用户有无访问此页面的权限。也就是说每个视图函数都需要用同一段代码,实现用一个功能。

    方法有两个:装饰器,中间件。在这里,中间件是更好的选择。

    来吧,写一个中间件。

    补充知识:

    process_request(request)

    request是一个HttpRequest 对象。

    在Django决定执行哪个视图之前,process_request()会在每个请求上调用。

    它应该返回一个None 或一个HttpResponse对象。如果返回None,Django会继续处理这个请求,执行其它process_request()中间件,然后process_view()中间件,最后是对应的视图。如果它返回一个HttpResponse对象,Django 就不用再去调用其它的request、view 或exception 中间件,或对应的视图;它将对HttpResponse 运用响应阶段的中间件,并返回结果。

     

    所以,在中间件中,有问题返回Httpresponse对象,不在调用其他中间件了。如果没问题,则返回None。

    同时,在视图函数中,需要对 条件判断的进行修正,将 会出问题的判断放在 if 语句中。

    views文件中

    def userselect(request):
        '''
        根据有无权限,
        显示所有的用户信息
        :param request:
        :return:
        '''
    
        url_list=request.session.get('url_list')
        flag = False
        for url in url_list:
            if re.match(url,request.path_info):
                flag=True
                break
        if not flag:
            return HttpResponse('无权访问')
        users = UserInfo.objects.all()
        return render(request, 'userselect.html', {'users': users})

    然后将其整体移植到自定义的中间件中。将自定义的 中间件写入设置。

    最终如下:

    中间件:

    from django.utils.deprecation import MiddlewareMixin
    class RbacMiddleware(MiddlewareMixin):
        def process_request(self,requst):
            url_list = request.session.get('url_list')
            flag = False
            for url in url_list:
                if re.match(url, request.path_info):
                    flag = True
                    break
            if not flag:
                return HttpResponse('无权访问')
            return None

    视图函数:

    def userselect(request):
        '''
        根据有无权限,
        显示所有的用户信息
        :param request:
        :return:
        '''
        users = UserInfo.objects.all()
        return render(request, 'userselect.html', {'users': users})

    settings文件:

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'rbac.middlewares.rbac.RbacMiddleware',
    ]

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    小改动

    统一加上了中间件,但是有一点小问题。当登录login页面是,也是返回无权访问。需要经login设为白名单。

    在中间件中加一行代码即可。

      

    from django.shortcuts import render,redirect,HttpResponse
    import re
    from django.utils.deprecation import MiddlewareMixin
    class RbacMiddleware(MiddlewareMixin):
        def process_request(self,request):
            if request.path_info=='/login/':
                return None
            if request.path_info=='/admin/':
                return None
            url_list = request.session.get('url_list')
            flag = False
            for url in url_list:
                if re.match(url, request.path_info):
                    flag = True
                    break
            if not flag:
                return HttpResponse('无权访问')
            return None

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    微调使文件更具有可读性

      在解决中间件问题后,用户登录成功后,将权限放入其session中,经过这样一个初始化操作。因为有可能开发另外一个系统,也会经历这个初始化操作。所以。选择将其拿出来写作一个函数,写入一个单独的文件中service/init_permission.py。

      

    views文件:

    import re
    # Create your views here.
    from rbac.models import *
    from rbac.service.init_permission import init_permission
    def login(request):
        if request.method=='POST':
            username=request.POST.get('username')
            password=request.POST.get('password')
            user=UserInfo.objects.filter(name=username,pwd=password).first()
            # print(user,type(user))
            if user:
                init_permission(user,request)
                return HttpResponse('登录成功')
    
        return render(request,'login.html')

    service/init_permission

    def init_permission(user,request):
        # permission_list = user.roles.all().values('permissions__name', 'permissions__url').distinct()
        permission_list = user.roles.filter(permissions__name__isnull=False).values('permissions__name', 'permissions__url').distinct()
    
        url_list = []
        for item in permission_list:
            url_list.append(item.get('permissions__url'))
        request.session['url_list'] = url_list

    补充一个小知识:

    isnull

    值为 True 或 False, 相当于 SQL语句IS NULLIS NOT NULL.

    例:

     

    Entry.objects.filter(pub_date__isnull=True)
    

    SQL等效:

    SELECT ... WHERE pub_date IS NULL;

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    代码需要润色的几点

      1 白名单可能有很多,将这些白名单写在settings文件中,从settings文件中读取,更合理。

      注释的是更正之前的代码。

    from django.shortcuts import render,redirect,HttpResponse
    import re
    from django.utils.deprecation import MiddlewareMixin
    from permission import settings
    class RbacMiddleware(MiddlewareMixin):
        def process_request(self,request):
            #1 获取白名单
            permission_valid_url=settings.PERMISSION_VALID_URL
            for url in permission_valid_url:
                if re.match(url,request.path_info):
                    return None
            # if request.path_info=='/login/':
            #     return None
            # if request.path_info=='/admin/':
            #     return None
            #2 获取权限
            url_list = request.session.get('url_list')
            #3 对用户请求的url进行匹配
            flag = False
            for url in url_list:
                if re.match(url, request.path_info):
                    flag = True
                    break
            if not flag:
                return HttpResponse('无权访问')
            return None

      2 request.session.get('url_list'),可能会在这个项目的很多地方用到,对于这种可能会用到很多次,可以将其写在配置文件中。

      在此项目中,两处需要修改。

      中间件中:

    from django.shortcuts import render,redirect,HttpResponse
    import re
    from django.utils.deprecation import MiddlewareMixin
    from django.conf import settings
    class RbacMiddleware(MiddlewareMixin):
        def process_request(self,request):
            #1 获取白名单
            permission_valid_url=settings.PERMISSION_VALID_URL
            for url in permission_valid_url:
                if re.match(url,request.path_info):
                    return None
            # if request.path_info=='/login/':
            #     return None
            # if request.path_info=='/admin/':
            #     return None
            #2 获取权限
            url_list = request.session.get(settings.PERMISSION_SESSION_KEY)
            # url_list = request.session.get('url_list')
            if not  url_list:
                return HttpResponse('未能读取到该用户的信息')
            #3 对用户请求的url进行匹配
            flag = False
            for url in url_list:
                if re.match(url, request.path_info):
                    flag = True
                    break
            if not flag:
                return HttpResponse('无权访问')
            return None

      init_permission初始化文件中:

    from django.conf import settings
    def init_permission(user,request):
        # permission_list = user.roles.all().values('permissions__name', 'permissions__url').distinct()
        permission_list = user.roles.filter(permissions__name__isnull=False).values('permissions__name', 'permissions__url').distinct()
    
        url_list = []
        for item in permission_list:
            url_list.append(item.get('permissions__url'))
        request.session[settings.PERMISSION_SESSION_KEY] = url_list
        # request.session['url_list'] = url_list

      settings文件中添加的两条配置:

    PERMISSION_VALID_URL=[
        '/login/',
        '/admin/.*',
    
    ]
    PERMISSION_SESSION_KEY='url_list'

      最后:目录结构如下

      

  • 相关阅读:
    [HNOI2007]最小矩形覆盖
    [HAOI2008]下落的圆盘
    JSON相关 JSON在线解析 JSON压缩转义工具 JSON着色工具 JSON 在线格式化工具 在线XML/JSON互相转换工具 XML、JSON在线转换
    速度竟差9倍!6款32GB USB3.0优盘横评
    Linux 中用 dd 命令来测试硬盘读写速度
    CrystalDiskMark v7.0.0h中文版
    个人觉得,不单是教育缺失的问题,贫穷才是真像。贫穷分
    就算是3.0的U盘,写入速度10M及以下也是正常的,U盘用很差的闪存颗粒的话就算10Gbps的USB3.1也是很慢的。
    USB历代标准及接口发展
    测试 USB 存储设备读写性能(Mb/s),平均读写速度等
  • 原文地址:https://www.cnblogs.com/654321cc/p/8318911.html
Copyright © 2011-2022 走看看