单爆手

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1. CRM项目回顾(纸笔黑画流程图): 1. 项目大体情况 客户管理系统/物料管理系统/库存管理系统/会员管理系统 职责:让公司销售管理我们的客户,会有持续的跟进记录,成单,关单,根据关单算销售提成 2.项目架构: Django+MySQL+Bootstrap 3. 关键技术点 1. auth模块--做用户认证注册 2. form和ModelForm做数据的增删改查 3. admin做管理界面(后台管理员) 4. formset 4. 业务流程 1. 网络咨询师工作-->录入客户信息-->加入公户 2. 销售工作: 1. --> 把公户转为私户 2. --> 记录沟通记录 --> 放回公户(搞不定的客户) 3. --> (搞定的客户)报名--指定班级 4. --> 缴费 3. 班主任工作: 1. --> 创建班级 2. --> 课程记录(记录课程记录:每天的上课记录day01~day120) 3. --> 学习记录(记录每位同学的考勤和作业成绩) 5. 这个项目你收获最大的是什么?/你遇到的最大的难题是什么? 1. 分页 --> 基本封装 2. 建表 --> 数据库三大范式 3. 类继承的应用: 1. 封装固定的功能到父类中 1. BootstrapBaseForm 2. auth模块的Abstractser 4. 反射应用: 1. settings.py中定制配置项(优雅的获取配置文件(让代码更健壮)--用反射去取settings中配置项) if hasattr(settings, 'WHITE_URL'):#代码中加判断settings模块中有无white_url配置项 WHITE_URL = getattr(settings, 'WHITE_URL')#有就取 else:#无则设一默认值 WHITE_URL = [] 2. 批量操作: 1. 为减少代码的冗余:用反射判断我当前视图cbv中有无以下划线开头的方法,就是通过反射实现这些私有方法 _to_public() _to_private() _multi_init() 5. 数据库ORM: 1. bulk_create(之前创建时销售人员多时老是感觉项目运行有点慢,后来就做代码的重构/审查发现把两嵌套的for循环做初始化时创建一个提交一个,所以系统大量时间都浪费在建立与断开数据库连接上),后来就用orm的bulk_create方法-->专门用来提供批量创建数据时的效率--多个数据一起提交 2. 事务操作和行级锁 --> 当时存在多个销售争抢同一个客户--怎么保证先到先得数据-->加行级锁(某条记录我更新完后别人才能对它操作) 6. QueryDict 1. 学会看源码:发现querydict对象有mutable参数 --> 我配置mutable=True时才能修改 2. 还看Form源码的is_valid()-->发现在内部可以定义自己的局部/全局的Hook(勾子)方法--如确认密码校验时就用到全局勾子 2. 权限系统介绍: 1. 分析问题 1. 什么是权限? 同一套系统不同的用户可以有不同的权限 2. 为什么需要权限? 不用岗位的人能做的事情不一样的 3. 如何实现权限控制? RBAC(专业术语--基于角色的权限控制系统--不同用户不同功能) 2. 写代码 1. 建表 录入信息 1. 安装xlrd模块pip install xlrd,专门用来操作excel文件(python操作excel文件的模块) 2. 如何在Django项目实现权限控制 1. 访问某个URL的时候,要判断这个URL在不在我的权限列表里面 2. 在中间件的process_request方法中对请求做权限判断 1. 先拿到访问的URL --> request.path_info 2. 获取当前用户的权限有哪些(哪些url) 1. 必须登录 --> 登录之后才能拿到用户,有了用户才能查询该用户的权限有哪些
(怎么查权限?--通过用户查角色,通过角色查对应权限--跨两表太慢,所以提前把用户信息存到session中下次用户来时直接session查不用再连表了--request.session就可获取,django默认把session存到django_session表中,一般redis,但这里我直接session中)
1. 把当前登录的用户的权限信息保存到session数据中 2. 每次请求来 从当前请求的session数据中拿到该用户的权限信息 3. 中间件中判断是否有权限 1. 不能简单的用in操作 2. 给权限判断设置白名单

 一.权限系统介绍

 

   打开我的luffy_permission项目(效果如图上)这里是我把权限组件在此项目中写,新建app做权限的rbac--python manage.py startapp rbac.

  在命令行创建的app一定要注册下告诉django项目,settings.py中--'rbac.apps.RbacConfig',

(1)models.py中建三表:

:  权限表中存的是权限--其实存的就是url(权限不一样即访问的url不一样)---存web项目的url

.  上图中可看出,用户和角色有多对多的关系,我把多对多建立在用户表(因为查询权限的时候有用户查权限查的较多--所以多对多字段设在查询较多的表中)。

  角色与权限也是多对多关系,把多对多放角色表中,因为角色查的多。(并改成中文名)

from django.db import models

#权限表
class Permission(models.Model):
    title = models.CharField(max_length=32)
    url = models.CharField(max_length=32)
    def __str__(self):
        return self.title
    class Meta:
        verbose_name = '权限'
        verbose_name_plural = verbose_name
#用户表
class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    roles = models.ManyToManyField(to='Role')
    class Meta:
        verbose_name = '用户'
        verbose_name_plural = verbose_name

#角色表
class Role(models.Model):
    title = models.CharField(max_length=32)
    permissions = models.ManyToManyField(to='Permission')
    class Meta:
        verbose_name = '角色'
        verbose_name_plural = verbose_name

然后建表--python manage.py makemigrations-python manage.py migrate

(2)rbac/admin.py:录入数据---用django 的admin:

  先在rbac中admin.py中把上述几个表注册

 然后创建超级用户:python manage.py createsuperuser -----lizhihua  lzh12345

  http://127.0.0.1:8007/admin/登录后如下图中在权限中分别录入如下数据:

        

   添加完后,权限页面中显示的是Permission object而没有刚才录入的内容,所以要在models.py中给权限表设置__str__方法返回字符串--结果如上图3中所示.

  且我想在权限页面中展示权限同时展示它对应的url--在adimn中自定制权限表的类list_display中加入字段即可效果如上图4中所示.

  且上图4中是展示url了但是不支持修改,---admin中自定制的类中list_editable中加入字段即可.效果如上图5所示.

from django.contrib import admin
from rbac.models import UserInfo,Permission,Role
#自定制一权限类的adimn--并把这类传给models就行
class PermissionAdmin(admin.ModelAdmin):#用这个类去控制权限表在admin管理后台的显示效果
    list_display =  ['title','url'] #就是在adimn页面上展示的字段有
    list_editable = ['url']  #告诉它哪个字段可支持编辑

admin.site.register(UserInfo)
admin.site.register(Permission,PermissionAdmin)#把定制类传进来
admin.site.register(Role)

 二.创建表和录入信息:

  

 

 1.录入信息

(1)如图1中,给各角色录入对应操作权限(Boss所有,经理无删除,销售无编辑,) 

(2)如上图2中分别建4个用户及对应角色.

 2.把权限系统应用入luffey_pression项目中.

  

上图中如何实现权限控制?---就是如你点击客户管理中的添加客户时它是跳转到/customer/add/这个url中的,所以就是判断这个url在不在某用户的权限列表中,在的话可以访问此url,不在则拒绝。这个逻辑相当于要给前端每个按钮绑定js事件,那页面上是js,后端没法知道对应权限是什么,若是发ajax请求那麻烦(点一次按钮发一次),

如下图这是一个url请求的走法:

   判断用户有无权限访问某url,就加到上图中间件部分中,且中间件的五个方法中的process_request方法中(请求来了就做判断)

三.登录之后保存权限信息:

(1)luffy_permission/urls.py:

from django.conf.urls import url,include
from django.contrib import admin
from rbac import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/$', views.login),
    url(r'^logout/$', views.logout),
    url(r'^', include('web.urls')),
]

(2)rbac/views.py中:这里我没用auth模块

from django.shortcuts import render
from rbac.models import UserInfo
from django.shortcuts import render, redirect, HttpResponse
from rbac.models import UserInfo
from django.conf import settings

def login(request):
    error_msg = ''  #默认空则不展示
    if request.method == 'POST':#登录时输入用户名密码点提交
        username = request.POST.get('username')
        pwd = request.POST.get('password')
        #注意filter得到的是query_set,user_obj是一对象,可以点属性,而query_set不能点,所以一定要加first
        user_obj = UserInfo.objects.filter(username=username,password=pwd).first()#拿到用户
        if user_obj:#登录成功
            #1.将当前登录用户的权限信息查询出来--且排除没权限的角色
            permission_queryset = user_obj.roles.all().filter(permissions__isnull=True).values_list('permissions__url')  #是query_set类型所以不能直接点来拿属性,可通过它的values方法来拿(字段双下划线就跨表拿了),这里用values_list列表(里边每一个元素是一小元组)
            permission_list = [i[0] for i in permission_queryset]#前边的i是列表中每一个元组拿出来,而我要存的不是元组是元组中第一个元素即(/customer/add/)这种url,所以i[0]
            # 2.将权限信息保存到session数据
            request.session['permission_url'] = permission_list
            return redirect('/customer/list/')
        else:
            error_msg = '用户名或密码错误'
    return render(request,'login.html',{'error_msg':error_msg})
def logout(request):
    request.session.flush()
    return redirect('/login/')

(3)rbac/templates/login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <input type="text" name="username">
    <input type="password" name="password">
    <input type="submit">
    <p>{{ error_msg }}</p>
</form>
</body>
</html>

         

 四.中间件中实现权限校验:

 (1)rbac/middleware.py:

  写一类必须继承。

  且得把此中间件在settings.py中注册'rbac.middleware.RBACMiddleware',

   且目当前访问的url是否在白名单中,建议把它写在settins.py中,因为后期会做动态修改

# 权限组件的相关配置

WHITE_URLS = [
'/login/',
'/logout/',
'/reg/',
'/admin/.*',
]
PERMISSION_SESSION_KEY = 'permission_url'

   #把session的key也做成一配置项放settings.py,因为我后面在很多地方都用到它(不同模块中可能用到的变量通常放到一公认配置文件中),PERMISSION_SESSION_KEY = 'permission_url'


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

class RBACMiddleware(MiddlewareMixin):
def process_request(self, request):#传当前请求的request
# 1. 获取当前请求的URL
current_url = request.path_info
# 判断settings模块中是否配置了WHITE_URLS
while_urls = getattr(settings, 'WHITE_URLS', [])
# 2.判断当前访问的url是否在白名单中
for url in while_urls:
if re.match(r'^{}$'.format(url), current_url):
return # 如果是白名单的Url则直接放行
# 判断当前这次请求的URL在不在权限列表里面
# 3. 当前登陆的这个人他的权限列表是什么
key = getattr(settings, 'PERMISSION_SESSION_KEY', 'permission_list')
permission_list = request.session.get(key, [])
# 4. 因为Django URL存在模糊匹配,所以校验权限的时候也要用正则去匹配
for pattern in permission_list:
if re.match('^{}$'.format(pattern), current_url):#match是从头开始匹配,search是只要包含就可以,findall是从头开始找到所有匹配项
#匹配上说明有权限
return None
else:
return HttpResponse('没有权限')
 

(2)rbac/views.py中:


from django.shortcuts import render, redirect, HttpResponse
from rbac.models import UserInfo
from django.conf import settings
# Create your views here.


def login(request):
error_msg = '' #默认空则不展示
if request.method == 'POST':#登录时输入用户名密码点提交
username = request.POST.get('username')
pwd = request.POST.get('password')
#注意filter得到的是query_set,user_obj是一对象,可以点属性,而query_set不能点,所以一定要加first
user_obj = UserInfo.objects.filter(username=username, password=pwd).first()
if user_obj:
# 登陆成功
# 1. 将当前登录用户的权限信息查询出来
# user_obj.roles.all() # QuerySet
#前边的i是列表中每一个元组拿出来,而我要存的不是元组是元组中第一个元素即(/customer/add/)这种url,所以i[0]
permission_queryset = user_obj.roles.all().filter(permissions__isnull=False).values_list('permissions__url')
permission_list = [i[0] for i in permission_queryset]
# 2. 将权限信息保存到session数据中
key = getattr(settings, 'PERMISSION_SESSION_KEY', 'permission_list')
request.session[key] = permission_list
return redirect('/customer/list/')
else:
error_msg = '用户名或密码错误'
return render(request, 'login.html', {'error_msg': error_msg})


def logout(request):
request.session.flush()
return redirect('/login/')
 

 效果如下图:当图1中用户王帅(角色是boss所以可操作图2中的所有增删改查),但换夏雨(实习生角色)用户登录时登录不上去。

  

 

posted on 2020-04-20 10:14  单爆手  阅读(471)  评论(0)    收藏  举报