zoukankan      html  css  js  c++  java
  • CRM项目之RBAC权限组件

    写在前面



        世间安得双全法 不负如来不负卿



      1 s17day26 CRM项目
      2 
      3 项目概要:XX公司CRM
      4     - 权限管理,公共组件,app      *****
      5     - 熟悉增删改查,Low            ***
      6     - 增删改查组件,公共组件,app  ****
      7 
      8 内容回顾:
      9     1. .all,values,values_list
     10         models.xx.objects.all()      
     11         ---> [obj,obj,obj,]
     12         models.xx.objects.values('id','name')
     13         ---> [{"id":1,'name':'兴普'},{"id":2,'name':'兴普1'},]
     14         models.xx.objects.values_list('id','name')
     15         ---> [(1,'兴普'),(2,'记不住就别来了')]
     16 
     17     2. 中间件是什么?有什么作用?
     18         
     19         class Md1:
     20             
     21             def process_request(self,request):
     22                 pass
     23                 
     24             class process_response(self,request,response):
     25                 return response
     26                 
     27         class Md2:
     28             
     29             def process_request(self,request):
     30                 pass
     31                 
     32             class process_response(self,request,response):
     33                 return response
     34             
     35             
     36             
     37         MIDDLEWARE = [
     38         
     39             "xxxxx.xxxx.Md1",
     40             "xxxxx.xxxx.Md2"
     41         ]
     42         
     43     3. ORM创建表
     44     
     45         FK常用操作
     46             class A(Model):
     47                 name = models.CharField(...)
     48         
     49             
     50             class B(Model):
     51                 name = models.CharField(...)
     52                 fk = models.FK(A)
     53             
     54             a. B表中有几列
     55                 id
     56                 name
     57                 fk_id
     58             
     59             b. 跨表操作
     60                 b_list = models.B.objects.all()
     61                 for item in b_list:
     62                     item.id
     63                     item.name
     64                     item.fk_id
     65                     item.fk
     66                     item.fk.name
     67                     item.fk.id 
     68             c. 跨表操作
     69                 b_list = models.B.objects.values('id','name','fk_id','fk__name')
     70                 for item in b_list:
     71                     item['id']
     72                     item['name']
     73                     item['fk_id']
     74                     item['fk__name']
     75         
     76             d. 跨表操作
     77                 b_list = models.B.objects.vlaues_list('id','name','fk_id','fk__name')
     78                 for item in b_list:
     79                     item[0]
     80                     item[1]
     81                     item[2']
     82                     item[3]
     83             e. 找A名称=“吴一飞”所有B表中的数据
     84                 models.B.objects.filter(fk__name='吴一飞')
     85                 
     86         M2M常用操作:
     87         
     88             class A(Model):
     89                 name = models.CharField(...)
     90             
     91             
     92             class B(Model):
     93                 name = models.CharField(...)
     94                 m = models.M2M(A)
     95         
     96             
     97             a. B表中有几列
     98                 id
     99                 name
    100                 
    101                 PS: 自动生成一个第三张表;m用于间接的对第三张表进行操作
    102                 
    103             b. 在B表中插入三条数据;A表中插入2条数据
    104                 models.A.objects.create(name='赵峰分')
    105                 models.A.objects.create(name='王勇')
    106                 models.A.objects.create(name='刘宏伟')
    107                 
    108                 
    109                 models.B.objects.create(name='兴普')
    110                 models.B.objects.create(name='香姐')
    111                 models.B.objects.create(name='名扬')
    112             
    113             c. 兴普和【赵峰分,王勇,刘宏伟】创建关系
    114             
    115                 obj = models.B.objects.create(name='兴普')
    116                 obj.m.add(1)
    117                 obj.m.add(2)
    118                 obj.m.add(3)
    119                 obj.m.add(*[1,2,3])
    120         
    121             d. 查找和兴普有关系的男人?
    122                 obj = models.B.objects.create(name='兴普')
    123                 obj.m.all() [A—obj,A—obj,A—obj]    
    124                 
    125     4. Session是什么?和Cookie有什么区别?
    126         
    127     5. 正则表达式
    128     
    129         re.match()
    130         
    131         ^ 
    132         
    133         $
    134         
    135         
    136 示例程序:pro_crm
    137         员工模块:
    138             权限,根据含有正则表达式URL进行分配
    139             操作,通过配置文件进行定制
    140         学生模块:
    141             问卷
    142             
    143         
    144         
    145 今日内容:
    146 
    147     权限:授权
    148 
    149         s17crm
    150             - app01
    151             - rbac
    152                 - models.py
    153         
    154         第一版:
    155             1. 权限表(含有正则表达式),permission
    156             
    157                 id         url                        title 
    158                  1      /userinfo/                   用户列表
    159                  2      /userinfo/(d+)/delete/      删除用户
    160                  3      /userinfo/(d+)/change/      修改用户
    161                  4      /userinfo/add/               添加用户
    162                  
    163                  
    164             2. 用户表,userinfo
    165                 id       username      password    
    166                  1        yql            123         
    167                  2        wxp            123         
    168                  3        zmx            123         
    169                  4        ll             123         
    170                 
    171                 
    172             3. 用户和权限关系表
    173                 id   用户ID    权限ID
    174                        1         1
    175                        2         1
    176                        2         2
    177                        2         3
    178                        2         4
    179                        3         1
    180                        4         1
    181                        4         2
    182                        4         3
    183                        4         4
    184             问题:用户分配权限时,麻烦
    185             
    186         第二版:
    187             
    188             0. 权限组,group
    189                 id          title 
    190                  1        用户组
    191                  2        订单组
    192             
    193             
    194             
    195             1. 权限表(含有正则表达式),permission
    196             
    197                 id         url                        title                code            group_i1       is_menu
    198                  1      /userinfo/                   用户列表              list               1            true
    199                  2      /userinfo/(d+)/delete/      删除用户              del                1            false
    200                  3      /userinfo/(d+)/change/      修改用户              edit               1            false
    201                  4      /userinfo/add/               添加用户              add                1            true
    202                  5      /order/add/                  ...                   add                2            true
    203                  6      /order/(d+)/delete/                               del                2            false
    204                  7      /order/(d+)/change/                               edit               2            false
    205                  8      /order/                                            list               2            true
    206                  
    207                  
    208             2. 用户表,userinfo
    209                 id       username      password    
    210                  1        yql            123         
    211                  2        wxp            123         
    212                  3        zmx            123         
    213                  4        ll             123    
    214             
    215             
    216             3. 角色表,role
    217                 id       title 
    218                  1       销售员
    219                  2       销售经理
    220                  3       市场专员
    221                  4       市场经理
    222                  5       IT
    223                  6       CTO
    224                  7       销售市场总监
    225                  8       CEO
    226                 
    227             4. 用户角色关系表
    228                 用户ID      角色ID
    229                  1           1
    230                  2           1
    231                  2           2
    232                  3           1
    233                  3           2
    234                  3           7
    235                 
    236             5. 角色和权限关系表
    237                 角色ID      权限ID
    238                   1           1
    239                   2           1
    240                   2           4
    241                   7           1
    242                   7           3
    243                   7           4
    244                   8           1
    245                   8           2
    246                   8           3
    247                   8           4
    248                 
    249             
    250             注意:根据用户找权限
    251                 - 用户具有的所有角色
    252                 - 再根据角色找所有权限(去重)
    253                 
    254             
    255         中午作业:
    256             - 填充数据
    257             - id=1的用户,
    258                 - 找具有所有角色
    259                 - 找到所有权限
    260                 - 找到所有权限(去重)
    261                 
    262         填充数据:
    263             基于Django Admin数据填充
    264             
    265             
    266         补充:不要相信你的眼睛
    267         
    268         分配权限:
    269             销售员:用户列表
    270                 孟祥杰
    271                 王勇 
    272                     
    273             销售经理:用户列表,添加用户
    274                 银秋良
    275                 
    276             总监: 用户列表,添加用户,订单列表
    277                 兴普
    278                 
    279             CEO:....
    280                 刘磊
    281                 
    282         
    283         
    284         注意:Djang Admin进行添加权限或授权
    285         
    286     权限: 自动生成菜单
    287         
    288         1. 获取数据
    289             
    290             [
    291                 {'menu_id': 4, 'menu_title': '用户管理菜单', 'title': '用户列表', 'url': '/userinfo/'}, 
    292                 {'opened':True,'menu_id': 4, 'menu_title': '用户管理菜单', 'title': '订单列表', 'url': '/order/'}, 
    293 
    294                 {'menu_id': 6, 'menu_title': '权限管理菜单', 'title': 'xxx列表', 'url': '/order/add/'}
    295                 {'menu_id': 6, 'menu_title': '权限管理菜单', 'title': 'xx列表', 'url': '/order/add/'}
    296             ]
    297             
    298         2. 根据数据创建两级菜单
    299             用户管理菜单
    300                 用户列表!
    301                 订单列表
    302             权限管理菜单
    303                 xxx列表
    304                 xx列表
    305                     
    306         
    307             思路:
    308                 page_menu = {
    309                     4:{'menu_id':4,'menu_title':'用户管理菜单','children': [{ 'title': '用户列表', 'url': '/userinfo/'},{'title': '订单列表', 'url': '/order/'}  ]}
    310                     6: {'menu_id':4,'menu_title':'权限管理菜单','children': [{ 'title': '用户列表', 'url': '/userinfo/'},{'title': '订单列表', 'url': '/order/'}  ]}
    311                 }
    312             
    313             
    314                 current_url = request.path_info
    315                 
    316                 
    317                 for item in permission_menu_list:
    318                     url = item['url']
    319                     regex = xxx.format(url)
    320                     if re.match(regex,current_url):
    321                         item['opened'] = True
    322                     
    323                     menu_id = item['menu_id']
    324                     opened = "active" if item.get('opened') else ""
    325                     
    326                     
    327                     child = {'title':item['title'],'url':item['url'],'opened': opened}
    328                     if menu_id in page_menu:
    329                         page_menu[menu_id]['children'].append(child)
    330                         if opened:
    331                             page_menu[menu_id]['opened'] = opened
    332                     else:
    333                         page_menu[menu_id] = {'opened':opened, 'menu_title': item['menu_title'], 'children': [child, ]}
    334                         
    335 总结:
    336 
    337     1. 表结构设计
    338     
    339     2. 录入数据
    340     
    341     3. 用户登录:
    342         - 获取角色
    343         - 获取权限
    344         - 对权限去重
    345         
    346     4. 结构,权限信息
    347         {
    348             1: {
    349                 'urls': ['/userinfo/', '/userinfo/add/', '/userinfo/(\d+)/delete/', '/userinfo/(\d+)/change/'], 
    350                 'codes': ['list', 'add', 'del', 'edit']
    351             }, 
    352             2: {
    353                 'urls': ['/order/', '/order/add/', '/order/(\d+)/delete/', '/order/(\d+)/change/'], 
    354                 'codes': ['list', 'add', 'del', 'edit']
    355             }
    356             
    357         }
    358         放入session中
    359     5. 中间件 
    360         白名单
    361         request.path_info
    362         session获取权限,进行验证
    363         
    364     6. 自动生成菜单 
    365         - inclusion_tag
    366         - 母版
    367         
    368     7. Django Admin 
    369         
    370         
    371         
    372 权限app中写代码:
    373     - 中间件 
    374     - init_permission
    375     - models 
    376     - admin 
    377     - templatetags
    378     
    379     依赖配置文件:
    380         XX = "permission_dict"
    381         OO = "permission_menu_list"
    382         RBAC_LOGIN_URL = "/login/"
    383         URL_FORMAT = "^{0}$"
    384 
    385         VALID_URL_LIST = [
    386             "^/login/$",
    387             "^/admin.*",
    388         ]
    389 
    390     
    391 使用权限管理:
    392     1. 创建cmdb project
    393     2. rbac拷贝到项目中
    394     3. 在settings.APP中将 rbac 注册
    395     4. 在settings中设置
    396             XX = "permission_dict"
    397             OO = "permission_menu_list"
    398             RBAC_LOGIN_URL = "/login/"
    399             URL_FORMAT = "^{0}$"
    400 
    401             VALID_URL_LIST = [
    402                 "^/login/$",
    403                 "^/admin.*",
    404             ]
    405     5. 开发CMDB完成
    406     
    407     6. 中间件中注册
    408     7. 利用temaplatetags和母版获取动态菜单
    409     
    410     8. 在Django Admin中操作权限信息
    411 
    412 
    413 作业:
    414     1. 权限系统:4天
    415     2. 自己创建一个主机管理系统:
    416         - 主机
    417         - 主机组
    418         - 部门
    419         - 机房
    420     3. 使用 权限系统[10天]
    武Sir - 笔记

    一、内容回顾

    - .all  .values  .values_list
    	models.xxx.objects.all()      				--> [obj,obj,obj,...]
    	models.xxx.objects.values('id','name')      --> [{'id':1,'name':'alex'},{'id':2,'name':'standby'},...]
    	models.xxx.objects.values_list('id','name') --> [(1,'alex'),(2,'standby',....)]
    
    
    - 中间件是什么?有什么用?
    	可以拦截所有的请求和响应,进行一些处理
    	中间件执行时有序的,从上到下执行,如果当前中间件不允许过,那么就不会再执行后面的中间件
    	比如说:对用户的请求做下黑名单
    
    	process_request() 默认没有返回值,即返回None; 则继续往下执行
    	但是如果有返回值,则不再继续往下执行,直接返回;
    
    	每个中间件就是一个类:
    		class Md1:
    			def process_request(self,request):
    				pass
    			def process_response(self,request,response):
    				return response
    		class Md2:
    			def process_request(self,request):
    				pass
    			def process_response(self,request,response):
    				return response
    
    		settings.py里配置
    
    			MIDDLEWARE = [
    				"XXXXXX.XXXXX.Md1",
    				"XXXXXX.XXXXX.Md2",
    			]
    
    - ORM创建表
    
    	- ForeignKey常用操作
    		class A(Model):
    			name = models.CharField(...)
    
    		class B(Model):
    			name = models.CharField(...)
    			fk = models.ForeignKey(A)
    
    		a. B表中有几列:
    			id
    			name
    			fk_id
    
    		b. 跨表操作
    			b_list = models.B.objects.all()
    			for item in b_list:
    				item.id
    				item.name
    				item.fk
    				item.fk_id
    				item.fk.id
    				item.fk.name
    
    		c. 跨表操作
    			b_list = models.B.objects.values('id','name','fk_id','fk__name')
    			for item in b_list:
    				item['id']
    				item['name']
    				item['fk_id']
    				item['fk__name']
    
    		d. 跨表操作
    			b_list = models.B.objects.vlaues_list('id','name','fk_id','fk__name')
    			for item in b_list:
    				item[0]
    				item[1]
    				item[2]
    				item[3]
    
    		e. 找A表名称等于"alex"的所有B表中的数据  		*****
    			models.B.objects.filter(fk__name="alex")  good
    
    			models.B.objects.filter(fk.name="alex")   这个是不可以,需要验证!!!!!!
    
    
    
    	- M2M常用操作
    		class A(Model):
    			name = models.CharField(...)
    
    		class B(Model):
    			name = models.CharField(...)
    			m = models.ManyToMany(A)
    
    		a. B表中有几列?
    			id
    			name
    
    		PS:ManyToMany 会自动生成第三张表,字段m用于间接的对第三张表进行操作
    
    
    		b. 在B表中插入3条数据,A表中插入2条数据
    
    			models.A.objects.create(name='alex1')
    			models.A.objects.create(name='alex2')
    
    			models.B.objects.create(name='egon1')
    			models.B.objects.create(name='egon2')
    			models.B.objects.create(name='egon3')
    
    		c. 让 egon1 和 [alex1,alex2] 创建关系
    			obj = models.B.objects.filter('name'='egon1')
    			obj.m.add(*[1,2])
    
    		d. 查找和egon1有关系的人
    			obj = models.B.objects.filter('name'='egon1')
    			obj.m.all()  # 拿到了queryset对象集合,都是A表的对象
    
    
    - Session是什么? 和cookie有什么区别?
    	- session依赖cookie而存在
    	  - session是存储在服务端的键值对
    	  - cookie是存储在客户端浏览器里的键值对
    
    	- 用户第一次来访问主页,服务端生成一个随机字符串通过cookie返回给客户端
    	  同时服务端把这个字符串当做key存储在数据库表里(也可以存在其他地方),值可以为空
    
    	- 用户第二次发起登录请求则带上刚才的cookie和用户信息
    	  服务端则把用户信息(比如用户名密码)用某种方式存储在刚才随机字符串对应的值里
    	  这样就表示用户登录过了
    

      

    二、CRM项目介绍

      - CRM简介

    xxx公司的CRM项目
        - 权限管理 (写成一个公共的组件/app,适用于Django项目)     *****
        - low的增删改查					***
        - 增删改查的组件 (写成公共组件/app)			****
    
    
    
    - 员工模块
    	- 权限:根据 含有正则表达式的url 进行分配的
    	- 操作:通过配置文件进行定制
    - 学生模块
    	- 问卷
    

      - RBAC简介

    RBAC(Role-Based Access Control,基于角色的权限控制)
    就是用户通过角色与权限进行关联。
    
    简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。
    这样,就构造成“用户-角色-权限”的授权模型。
    
    在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。
    

      

    三、表结构设计

    - 第一版
    	- permission权限表(含有正则表达式的url)
    		id 			url                              title
    		1           /userinfo/                       用户列表 
    		2			/userinfo/(d+)/delete/          删除用户
    		3 			/userinfo/(d+)/change/          修改用户
    		4           /userinfo/add/                   添加用户 
    
    	- userinfo用户表
    		id     username   password    
    		1      alex       123
    		2      egon       123
    		3      standby    123
    
    	- 用户和权限的关系表
    		id     user_id    permission_id
    		1      1          1
    		2      1          2
    		3      2          1
    		4      3          1
    		5      3          2
    		6      3          3
    
    
    	问题:用户分配权限时,很麻烦,不方便后面的维护
    
    
    
    
    
    
    
    - 第二版
    	- permission权限表(含有正则表达式的url)
    		id 			url                              title
    		1           /userinfo/                       用户列表 
    		2			/userinfo/(d+)/delete/          删除用户
    		3 			/userinfo/(d+)/change/          修改用户
    		4           /userinfo/add/                   添加用户 
    
    	- userinfo用户表
    		id     username   password    
    		1      alex       123
    		2      egon       123
    		3      standby    123
    
    	- role 角色表
    		id      title
    		1		销售员
    		2		销售经理
    		3		市场专员
    		4		市场经理
    		5		IT 
    		6		CTO 
    		7		CEO
    
    	- 用户和角色关系表
    		id      user_id		role_id
    		1		1			1
    		2		2			1
    		3		2			2
    		4		3			1
    		5		3			2
    		6		3			7
    
    	- 角色和权限的关系表
    		id      role_id		permission_id
    		1		1			1
    		2		2			1
    		3		2			4
    		4		6			1
    		5		6			3
    		6		6			4
    		7		7			1
    		8		7			2
    		9		7			3
    		10		7			4	
    
    
    	列出standby所具有的所有权限,可能会重复,所以需要去重;
    	注意:根据用户找权限
    		- 根据用户找角色
    		- 根据角色找权限
    
    
    	- 增加权限组表group
    		id 			title
    		1			用户组
    		2			订单组
    
    
    	- permission权限表 增加一个代号code字段、权限组字段以及 是否是菜单字段(涉及到在前端页面展示):
    		- permission权限表(含有正则表达式的url)
    		id 			url                           title 	     code     group_id    is_menu
    		1           /userinfo/                    用户列表       list     1           true
    		2			/userinfo/(d+)/delete/       删除用户       del      1           false
    		3 			/userinfo/(d+)/change/       修改用户       edit     1           false
    		4           /userinfo/add/                添加用户       add      1           true
    		5           /order/                       订单列表       list     2           true
    		6			/order/(d+)/delete/          删除订单       del      2           false
    		7 			/order/(d+)/change/          修改订单       edit     2           false
    		8           /order/add/                   添加订单       add      2           true
    

      

    class Group(models.Model):
        """
        权限组表
        """
        title = models.CharField(max_length=32)
    
        class Meta:
            verbose_name_plural = "权限组表"
        def __str__(self):
            return self.title
    class Permission(models.Model):
        """
        权限表
        """
        title = models.CharField(verbose_name='标题',max_length=32)
        url = models.CharField(verbose_name="含正则的URL",max_length=128)
        code = models.CharField(verbose_name="权限代号",max_length=16)
        group = models.ForeignKey(verbose_name="权限组",to="Group")  # 把具体的权限分组管理,类似省市县
        is_menu = models.BooleanField(verbose_name="是否是菜单")      # 用来筛选出可以在左侧菜单展示的选项
        class Meta:
            verbose_name_plural = "权限表"
    
        def __str__(self):
            return self.title
    
    class UserInfo(models.Model):
        """
        用户表
        """
        username = models.CharField(verbose_name="用户名",max_length=32)
        password = models.CharField(verbose_name='密码',max_length=64)
        roles = models.ManyToManyField(verbose_name='具有所有角色',to="Role",blank=True)
    
        class Meta:
            verbose_name_plural = "用户表"
    
        def __str__(self):
            return self.username
    
    
    class Role(models.Model):
        """
        角色表
        """
        title = models.CharField(verbose_name='角色名称',max_length=32)
        permissions = models.ManyToManyField(verbose_name="具有所有权限",to='Permission',blank=True)
    
        class Meta:
            verbose_name_plural = "角色表"
    
        def __str__(self):
            return self.title
    

      

     

    让组和菜单创建关系     页面显示的时候是不显示组的

    组的存在只是为了在分配权限的时候方便一些:一个组下面的增删改查

    但是菜单的信息存储在哪呢?

        - 可以把菜单都存储在  Group表里

        - 增加parent字段,让某些组属于某个菜单(ORM里就是自关联,需要related_name字段)

        - 然后再增加一个is_group字段用来区分菜单

    补充:

        - 具体的权限只能在 组 下面,不能直接挂载菜单下面

    class Permission(models.Model):
        """
        权限表
        """
        title = models.CharField(verbose_name='标题',max_length=32)
        url = models.CharField(verbose_name="含正则的URL",max_length=128)
        code = models.CharField(verbose_name="权限代号",max_length=16)
        # group = models.ForeignKey(verbose_name="权限组",to="Group")  # 把具体的权限分组管理,类似省市县
        group = models.ForeignKey(verbose_name="权限组",to="Group",limit_choices_to={'is_group':True})
        is_menu = models.BooleanField(verbose_name="是否是菜单") # 用来筛选出可以在左侧菜单展示的选项
        class Meta:
            verbose_name_plural = "权限表"
    
        def __str__(self):
            return self.title
    

      

    group = models.ForeignKey(verbose_name="权限组",to="Group")
    group = models.ForeignKey(verbose_name="权限组",to="Group",limit_choices_to={'is_group':True})

     就是说:只有是组的时候才能做 Permission表的外键

     最终的表结构如下:

    class Group(models.Model):
        """
        权限组表
        """
        title = models.CharField(max_length=32)
        parent = models.ForeignKey(to="Group",related_name="xxx",null=True,blank=True)
        is_group = models.BooleanField(verbose_name="是否是组",default=True)
        
        class Meta:
            verbose_name_plural = "权限组表"
        def __str__(self):
            return self.title
        
    class Permission(models.Model):
        """
        权限表
        """
        title = models.CharField(verbose_name='标题',max_length=32)
        url = models.CharField(verbose_name="含正则的URL",max_length=128)
        code = models.CharField(verbose_name="权限代号",max_length=16)
        # group = models.ForeignKey(verbose_name="权限组",to="Group")  # 把具体的权限分组管理,类似省市县
        group = models.ForeignKey(verbose_name="权限组",to="Group",limit_choices_to={'is_group':True})
        is_menu = models.BooleanField(verbose_name="是否是菜单") # 用来筛选出可以在左侧菜单展示的选项
        
        class Meta:
            verbose_name_plural = "权限表"
    
        def __str__(self):
            return self.title
    
    class UserInfo(models.Model):
        """
        用户表
        """
        username = models.CharField(verbose_name="用户名",max_length=32)
        password = models.CharField(verbose_name='密码',max_length=64)
        roles = models.ManyToManyField(verbose_name='具有所有角色',to="Role",blank=True)
    
        class Meta:
            verbose_name_plural = "用户表"
    
        def __str__(self):
            return self.username
    
    
    class Role(models.Model):
        """
        角色表
        """
        title = models.CharField(verbose_name='角色名称',max_length=32)
        permissions = models.ManyToManyField(verbose_name="具有所有权限",to='Permission',blank=True)
    
        class Meta:
            verbose_name_plural = "角色表"
    
        def __str__(self):
            return self.title
    

      

    四、需求分析

    # 几点注意事项
    
    - 双下划线跨表取值
            - 外键和多对多  都可以用  __(双下划线)  跨表获取对应字段
            - user  -> 多个角色roles  ->  根据角色的permissions字段加 '__' 跨到权限表
    
    ```
    permission_list = user.roles.filter(permissions__id__isnull=False).values(
            'permissions__id',
            'permissions__title',
            'permissions__url',
            'permissions__code',
            'permissions__group',
            'permissions__is_menu'
        ).distinct()
    ```
    
    
    - 列表distinct()去重
            - [].distinct()  进行去重 
    
    
    - 自定义配置
    	- 在settings.py里定义好 (变量名一定要大写)
    	- 在代码里引入
    		Django的所有配置(既包含自定义的也包含Django内置的):
    		from django.conf import settings
    			
    
    - 找到某个用户所具有的权限
    	- 先查找所具有的角色
    	- 再查找所具有的权限
    	- 最后把权限去重
    
    
    - 自动生成权限菜单
    	- 获取数据
    	- 创建两级菜单
    	- 两级菜单生成
    		- 在视图函数中拼接好返回给前端
    		- @register.simple_tag()
    		- @register.inclusion_rag("menu_tpl.html")
    
    
    - 请求url验证中间件
            - 要在settings.py里维护一份白名单
            - 请求验证中间件依赖于session,所以自定义中间件的位置应该放在session中间件(SessionMiddleware)之后
            - 对用户请求的url和该用户所具有的权限要做正则匹配:re.match(patten, current_request_url)
    

     

    # 1/2/3 是组ID
    {
    	1: {
    		'urls': ['/userinfo/', '/userinfo/add/'], 
    		'codes': ['list', 'add']
    	}, 
    	2: {
    		'urls': ['/order/'], 
    		'codes': ['list']
    	}, 
    	3: {
    		'urls': ['/index/'], 
    		'codes': ['index']
    	}
    }
    
    
    [
    	{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/', 'permission_title': '用户列表'}, 
    	{'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/add/', 'permission_title': '添加用户'}, 
    	{'menu_id': 6, 'menu_title': '权限管理菜单', 'permission_url': '/permissioninfo/', 'permission_title': '权限列表'},
    	{'menu_id': 6, 'menu_title': '权限管理菜单', 'permission_url': '/permissioninfo/add', 'permission_title': '添加权限'}
    ]
    
    
    # 4/6 是菜单ID 
    # 菜单和组都在同一张表里,有父子关系,最后的目的是构造菜单和is_menu=True的权限item的两级菜单
    {
    	4:{
    		'opened':False,
    		'menu_title':'用户管理菜单',
    		'children': [
    			{'title': '用户列表', 'url': '/userinfo/', 'opened':False},
    			{'title': '订单列表', 'url': '/order/', 'opened':False,}
    		]
    	},
    	6: {	
    		'opened':False,
    		'menu_title':'权限管理菜单',
    		'children': [
    			{'title': '权限列表', 'url': '/userinfo/', 'opened':False},
    			{'title': '添加权限', 'url': '/order/', 'opened':False,}
    		]
    	}
    }
    总结:
    	- 表的设计(很重要)
    		4个类  6张表
    
    	- Django admin 录入数据
    	  
    	- 用户登录处理
      		- 获取角色
      		- 获取权限
      		- 对权限去重
    	  	- 然后把权限数据存储到session
    
    	- 登录中间件
    		- 白名单
    		- request.path_info
    		- 从session获取权限,进行验证
    
    	- 自动生成菜单 
    		- 跨表取出相关数据,转换字典结构
    		- 视图中生成好字典返回给前端
    		- 前端模板渲染
    
    		- simple_tag
    		- inclusion_rag
    		- 模板layout.html
    
    
    
    - 权限app包含哪些内容
    	- 中间件
    	- init_permission
    	- models
    	- admin 
    	- templatetags
    
    	依赖配置文件
    
    		PERMISSION_DICT = "permission_dict"
    		URL_FORMAT = "^{0}$"
    		RBAC_LOGIN_URL = "/login/"
    		VALID_URL_LIST = [
    		    "^/login/$",
    		    "^/admin.*",
    		]
    
    
    - 使用rbac权限管理
    	- 创建CMDB项目
    	- 把rbac拷贝到项目中
    	- 在settings.APP中注册 rbac 
    	- 在settings中配置相关变量:
    		PERMISSION_DICT = "permission_dict"
    		URL_FORMAT = "^{0}$"
    		RBAC_LOGIN_URL = "/login/"
    		VALID_URL_LIST = [
    		    "^/login/$",
    		    "^/admin.*",
    		]
    	- 开发CMDB
    	- 开启中间件验证
    	- 利用tmplatetags和模板动态生成菜单
    	- 在Django admin中操作权限信息
    
    
    
    
    
    练习
    	- 权限系统补充完整,搞清楚每一行代码  [4天]
    	- 自己创建project,比如主机管理系统
    		- 主机
    		- 主机组
    		- 部门
    		- 机房
    		- ...
    	- 使用rbac权限系统 [10天]
    

      

    五、代码实现

    表结构如上所述,此处略过...

    # 项目结构
    
    D:softworkPython_17day26homeworks17crm>tree /F
    卷 NewDisk 的文件夹 PATH 列表
    卷序列号为 2E8B-8205
    D:.
    │  db.sqlite3
    │  manage.py
    │
    │
    ├─app01
    │  │  admin.py
    │  │  apps.py
    │  │  models.py
    │  │  tests.py
    │  │  views.py
    │  └─ __init__.py
    │  
    │
    ├─rbac
    │  │  admin.py
    │  │  apps.py
    │  │  models.py
    │  │  tests.py
    │  │  views.py
    │  │  __init__.py
    │  │
    │  ├─middleware
    │  │  └─  rbac.py
    │  │  
    │  │
    │  ├─service
    │  │  │  init_permission.py
    │  │  │
    │  │  └─__pycache__
    │  │          init_permission.cpython-35.pyc
    │  │
    │  ├─templatetags
    │     │  menu_gennerator.py
    │     └─ __init__.py
    │  
    │
    ├─s17crm
    │  │  settings.py
    │  │  urls.py
    │  │  wsgi.py
    │  └─ __init__.py
    │
    ├─statics
    │  ├─css
    │  │      bbs.css
    │  │      bootstrap-select.min.css
    │  │      bootstrap-theme.css
    │  │      bootstrap-theme.css.map
    │  │      bootstrap-theme.min.css
    │  │      bootstrap-theme.min.css.map
    │  │      bootstrap.css
    │  │      bootstrap.css.map
    │  │      bootstrap.min.css
    │  │      bootstrap.min.css.map
    │  │      bootstrapValidator.min.css
    │  │
    │  ├─image
    │  │      header.png
    │  │
    │  └─js
    │          bootstrap-select.js.map
    │          bootstrap-select.min.js
    │          bootstrap.js
    │          bootstrap.min.js
    │          bootstrapValidator.min.js
    │          city_info.js
    │          jquery-3.2.1.js
    │          jquery-3.2.1.min.js
    │          jquery.cookie.js
    │          npm.js
    │
    └─templates
            index.html
            login.html
            menu_tpl.html
            order.html
            order_add.html
            tpl.html
            user.html
            user_add.html
    
    
    D:softworkPython_17day26homeworks17crm>
    

      

    # s17crm/app01/views.py
    
    from django.shortcuts import render,HttpResponse,redirect
    from django.forms import Form
    from django.forms import fields
    from django.forms import widgets
    from rbac import models
    from rbac.service.init_permission import init_permission
    from django.conf import settings
    
    class LoginForm(Form):
        username = fields.CharField(required=True,error_messages={'required':"用户名不能为空"})
        password = fields.CharField(required=True,error_messages={'required':"密码不能为空"})
    
    def login(request):
        if "GET" == request.method:
            form = LoginForm()
            return render(request,'login.html',{'form':form})
        else:
            form = LoginForm(data=request.POST)
            if form.is_valid():
                # 格式验证通过
                # 注意:只有当 LoginForm 里面变量名称和models表字段名称一致才能使用  **form.cleaned_data
                user = models.UserInfo.objects.filter(**form.cleaned_data).first()
                if user:
                    # 获取当前用户的权限信息做格式化然后存储到session中
                    init_permission(request,user)
                    print(request.session.get(settings.PERMISSION_DICT))
                    print(request.session.get(settings.PERMISSION_MENU_LIST))
                    return redirect('/index/')
                else:
                    from django.core.exceptions import ValidationError
                    form.add_error('password',ValidationError("用户名或密码错误!!!"))
    
            return render(request,'login.html',{'form':form})
    
    
    def index(request):
        # 通过 @register.inclusion_tag('menu_tpl.html') 构造菜单结构并渲染
        # 所以这里不用做处理
        return render(request,'index.html')
    
    
    def clear(request):
        # 手动清空session
        request.session.clear()
        return HttpResponse("已清除")
    
    
    def order(request):
        return render(request,'order.html')
    
    def order_add(request):
        return render(request,'order_add.html')
    
    def user(request):
        return render(request,'user.html')
    
    def user_add(request):
        return render(request,'user_add.html')
    

      

    # s17crm
    bacmiddleware
    bac.py
    # 用户访问鉴权中间件
    
    
    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    # 这是页面权限验证的中间件
    
    
    from django.shortcuts import HttpResponse,redirect
    from django.conf import settings
    import re
    
    
    class MiddlewareMixin(object):
        def __init__(self, get_response=None):
            self.get_response = get_response
            super(MiddlewareMixin, self).__init__()
    
        def __call__(self, request):
            response = None
            if hasattr(self, 'process_request'):
                response = self.process_request(request)
            if not response:
                response = self.get_response(request)
            if hasattr(self, 'process_response'):
                response = self.process_response(request, response)
            return response
    
    class RbacMiddleware(MiddlewareMixin):
        def process_request(self,request):
    
            # 1. 获取当前请求的 uri
            current_request_url = request.path_info
    
            # 2. 判断是否在白名单里,在则不进行验证,直接放行
            for url in settings.VALID_URL_LIST:
                if re.match(url, current_request_url):
                    return None
    
            # 3. 验证用户是否有访问权限
            flag = False
            permission_dict = request.session.get(settings.PERMISSION_DICT)
    
            print(permission_dict)
    
            # 如果没有登录过就直接跳转到登录页面
            if not permission_dict:
                return redirect(settings.RBAC_LOGIN_URL)
            """
                {
                    1: {
                        'codes': ['list', 'add'], 
                        'urls': ['/userinfo/', '/userinfo/add/']
                    }, 
                    2: {
                        'codes': ['list'], 
                        'urls': ['/order/']
                    }
                }
            """
            for group_id, values in permission_dict.items():
                for url in values['urls']:
                    # 必须精确匹配 URL : "^{0}$"
                    patten = settings.URL_FORMAT.format(url)
                    if re.match(patten, current_request_url):
                        flag = True
                        break
                if flag:
                    break
            if not flag:
                return HttpResponse("无权访问")
    

      

    # s17crm
    bacserviceinit_permission.py
    # 这是用户登录后初始化用户权限信息的模块
    
    
    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    
    from django.conf import settings
    
    def init_permission(request,user):
        # 获取当前用户的权限信息
        """
            外键和多对多  都可以用  __(双下划线)  跨表获取对应字段
            [].distinct()  进行去重 
        """
        permission_list = user.roles.filter(permissions__id__isnull=False).values(
            'permissions__id',
            'permissions__title',
            'permissions__url',
            'permissions__code',
            'permissions__group',
            'permissions__is_menu',
            'permissions__group__parent_id',        # 即:当前权限所在组的所属菜单ID
            'permissions__group__parent__title',    # 即:当前权限所在组的所属菜单名称
        ).distinct()
    
        # 格式化当前用户的权限信息
        """
            {
                1: {
                    'codes': ['list', 'add'], 
                    'urls': ['/userinfo/', '/userinfo/add/']
                }, 
                2: {
                    'codes': ['list'], 
                    'urls': ['/order/']
                }
            }
        """
        permission_dict = {}
        for item in permission_list:
            url = item.get('permissions__url')
            code = item.get('permissions__code')
            group_id = item.get('permissions__group')
            if group_id in permission_dict:
                permission_dict[group_id]['urls'].append(url)
                permission_dict[group_id]['codes'].append(code)
            else:
                permission_dict[group_id] = {'codes': [code, ], 'urls': [url, ]}
        # 把当前用户权限信息存储到session中
        request.session[settings.PERMISSION_DICT] = permission_dict
    
    
        # 格式化当前用户的菜单列表信息
        # 最终的目的就是要把菜单和具体的is_menu=True的权限item关联起来并在前端构成 两级菜单
        '''
            [
                {'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/', 'permission_title': '用户列表'}, 
                {'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/add/', 'permission_title': '添加用户'}, 
                {'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/order/', 'permission_title': '订单列表'}
            ]
        '''
        permission_menu_list = []
        for item in permission_list:
            if item['permissions__is_menu']:
                tmp = {
                    'menu_title':item['permissions__group__parent__title'],
                    'menu_id':item['permissions__group__parent_id'],
                    'permission_url':item['permissions__url'],
                    'permission_title':item['permissions__title'],
                }
                permission_menu_list.append(tmp)
        # 把当前用户菜单信息存储到session中
        request.session[settings.PERMISSION_MENU_LIST] = permission_menu_list
    
        # 设置session的超时时间:30min
        request.session.set_expiry(1800)
    
        # 为了要在前端构造出两级菜单,还需要对上面拿到的菜单列表做一下格式转换
        '''
            {
                4:{
                    'opened':False,
                    'menu_title':'用户管理菜单',
                    'children': [
                        {'title': '用户列表', 'url': '/userinfo/', 'opened':False},
                        {'title': '订单列表', 'url': '/order/', 'opened':False,}
                    ]
                },
                6: {	
                    'opened':False,
                    'menu_title':'权限管理菜单',
                    'children': [
                        {'title': '权限列表', 'url': '/xxxinfo/', 'opened':False},
                        {'title': '分类列表', 'url': '/xxxxxxxx/', 'opened':False,}
                    ]
                }
            }
        '''
    # s17crm
    bac	emplatetagsmenu_gennerator.py
    # 使用inclusion_tag渲染菜单显示在前端页面
    
    
    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    
    from django import template
    register = template.Library()
    
    import re
    from django.conf import settings
    
    '''
        [
            {'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/', 'permission_title': '用户列表'}, 
            {'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/userinfo/add/', 'permission_title': '添加用户'}, 
            {'menu_id': 4, 'menu_title': '用户管理菜单', 'permission_url': '/order/', 'permission_title': '订单列表'},
            ...
        ]
        
        转换成下面的结构,然后再前端进行展示
        
        {
            4:{
                'opened':False,
                'menu_title':'用户管理菜单',
                'children': [
                    {'title': '用户列表', 'url': '/userinfo/', 'opened':False},
                    {'title': '订单列表', 'url': '/order/', 'opened':False,}
                ]
            },
            6: {	
                'opened':False,
                'menu_title':'权限管理菜单',
                'children': [
                    {'title': '权限列表', 'url': '/xxxinfo/', 'opened':False},
                    {'title': '分类列表', 'url': '/xxxxxxxx/', 'opened':False,}
                ]
            },
            ...
        }
    '''
    
    @register.inclusion_tag('menu_tpl.html')
    def menu_show(request):
        permission_menu_dict = {}
        current_request_url = request.path_info
        permission_menu_list = request.session.get(settings.PERMISSION_MENU_LIST)
    
        for item in permission_menu_list:
            url = item['permission_url']
            patten = settings.URL_FORMAT.format(url)
            # 首先遍历所有的具体权限,与当前请求url做比较,匹配则把 opened置为 active,用于配合前端的 .active 属性
            opened = "active" if re.match(patten, current_request_url) else ""
    
            menu_id = item['menu_id']
            child = {'opened': opened, 'title': item['permission_title'], 'url': item['permission_url']}
            if menu_id in permission_menu_dict:
                # 更新已有menu
                permission_menu_dict[menu_id]['children'].append(child)
                if opened:
                    permission_menu_dict[menu_id]['opened'] = opened
            else:
                # 初始化一个menu
                permission_menu_dict[menu_id] = {
                    'opened': opened,
                    'menu_title': item['menu_title'],
                    'children': [child,]
                }
        return {'permission_menu_dict':permission_menu_dict}
    
    
    
    
    
    
    # s17crm	emplatesmenu_tpl.html
    
    
    {% for menu_id,item_dict in permission_menu_dict.items %}
         <div class="item">
            <div class="menu_title">
                <a href="#" class="{{ item_dict.opened }}">{{ item_dict.menu_title }}</a>
            </div>
            <div class="menu_items {{ item_dict.opened }}">
                {% for permission in item_dict.children %}
                    <a href={{ permission.url }} class="{{ permission.opened }}">{{ permission.title }}</a>
                {% endfor %}
            </div>
         </div>
    {% endfor %}
    

      

    # s17crm	emplateslogin.html
    
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <form method="post" novalidate>
        {% csrf_token %}
        <P>
            {{ form.username }} {{ form.errors.username.0 }}
        </P>
        <p>
            {{ form.password }} {{ form.errors.password.0 }}
        </p>
    
        <input type="submit" value="提交">
    </form>
    
    </body>
    </html>
    
    # s17crm	emplates	pl.html
    
    
    {% load staticfiles %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>###CRM</title>
        <link rel="Shortcut Icon" href="{% static "image/header.png" %}">
        <link rel="stylesheet" href="{% static "css/bootstrap.css" %}">
        <script src="{% static "js/jquery-3.2.1.min.js" %}"></script>
        <script src="{% static "js/bootstrap.js" %}"></script>
    
        <style>
            body {
                margin: 0;
                padding: 0;
            }
            .header {
                height: 40px;
                background-color: lightgreen;
                text-align: center;
                line-height: 40px;
            }
            .menu {
                float: left;
                 16%;
                background-color: wheat;
                min-height: 500px
            }
            .right_body {
                float: left;
                 84%;
                min-height: 500px;
            }
            .item .menu_title {
                font-size: 20px;
            }
            .item .menu_title a.active {
                color: green;
            }
            .item .menu_items {
                display: none;
            }
            .item .menu_items.active {
                display: block !important;
            }
            .item .menu_items a {
                font-size: 15px;
                display: block;
                padding-left: 20px;
            }
            .item .menu_items a.active {
                color: red;
            }
        </style>
    </head>
    <body>
    
    <div class="header">
        <h2>头部文字水平垂直居中显示...</h2>
    </div>
    
    {% load menu_gennerator %}
    <div class="content">
    
        <div class="menu">
            {% menu_show request %}
        </div>
    
        {% block content %}
    
            <h1>这个是模板页面...</h1>
    
        {% endblock %}
    
    </div>
    
    </body>
    <script>
        $(function () {
            menu_swith();
        });
        
        function menu_swith() {
            $(".menu_title").click(function () {
                if($(this).children().hasClass("active")) {
                    $(this).next().removeClass("active");
                    $(this).children().removeClass("active");
                }else {
                    $(this).children().addClass("active");
                    $(this).next().addClass("active");
                }
            })
        }
    
    </script>
    
    </html>
    

      

    # s17crm	emplatesindex.html
    
    
    {% extends "tpl.html" %}
    
    {% block content %}
    
    <div class="right_body">
        <h1>这是首页...</h1>
    </div>
    
    {% endblock %}
    
    
    
    
    # s17crm	emplatesorder.html
    
    
    {% extends "tpl.html" %}
    
    {% block content %}
    
    <div class="right_body">
        <h1>订单列表...</h1>
    </div>
    
    {% endblock %}
    
    
    
    
    
    # s17crm	emplatesorder_add.html
    
    
    {% extends "tpl.html" %}
    
    {% block content %}
    
    <div class="right_body">
        <h1>新增订单...</h1>
    </div>
    
    {% endblock %}
    
    
    ...
    

      

    # s17crms17crmurls.py
    
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/', views.login),
        url(r'^index/', views.index),
        url(r'^clear/', views.clear),
        url(r'^userinfo/$', views.user),
        url(r'^userinfo/add/$', views.user_add),
        url(r'^order/$', views.order),
        url(r'^order/add/$', views.order_add),
    ]
    

      

    # s17crms17crmsettings.py
    
    """
    Django settings for s17crm project.
    
    Generated by 'django-admin startproject' using Django 1.11.3.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/1.11/topics/settings/
    
    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/1.11/ref/settings/
    """
    
    import os
    
    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    
    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = '-dulev94(7c=_e_s!@ww937pu3rqiiszw1y(eyl3*mp$&5h_e2'
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    
    ALLOWED_HOSTS = []
    
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
        'rbac',
    ]
    
    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.middleware.rbac.RbacMiddleware'
    ]
    
    ROOT_URLCONF = 's17crm.urls'
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 's17crm.wsgi.application'
    
    
    # Database
    # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
    
    
    # Password validation
    # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    
    # Internationalization
    # https://docs.djangoproject.com/en/1.11/topics/i18n/
    
    LANGUAGE_CODE = 'en-us'
    
    TIME_ZONE = 'UTC'
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = True
    
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/1.11/howto/static-files/
    
    STATIC_URL = '/static/'                 #引用名
    # 配置STATICFILES_DIRS,指定额外的静态文件存储位置
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR,"statics"),    #实际名 ,即实际文件夹的名字
    )
    
    ##########################   自定义权限相关配置   ##################################
    
    PERMISSION_DICT = "permission_dict"
    PERMISSION_MENU_LIST = "permission_menu_list"
    URL_FORMAT = "^{0}$"
    RBAC_LOGIN_URL = "/login/"
    VALID_URL_LIST = [
        "^/login/$",
        "^/admin.*",
        "^/clear/$",
    ]
    

      

    作者:Standby一生热爱名山大川、草原沙漠,还有妹子
    出处:http://www.cnblogs.com/standby/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    HDU 3436 Queuejumpers
    POJ 3580 SuperMemo
    HDU 2871 Memory Control
    Android 实现显示文字的Gallery
    Android 使用地图
    Android 深入的研究一下蓝牙
    手机录制视频demo
    用android来实现图片的绘制以及旋转缩放案例分析
    TextView 自动滚动(跑马灯)
    Android腾讯微博客户端开发一:在下方的Tab的实现
  • 原文地址:https://www.cnblogs.com/standby/p/7801910.html
Copyright © 2011-2022 走看看