ITPub博客

关于自动化平台的动态菜单设计

原创 作者:jeanron100 时间:2018-01-06 09:42:26 0 删除 编辑

最近几天是马不停蹄的做一些事情,今天计划把通用功能的部分先改进一些,比如说菜单的权限配置。目前使用的方案是用户可以看到所有的菜单,如果没有权限,则返回一个权限不足的页面。

因为整个开发后面会有多个模块,而且有些功能其实放在一起会看起来有些庞大,所以我们可以做裁剪,就是你登录以后,你能看到你拥有权限的菜单。

事情可以天马行空的想,但是落到实处做的时候,发现还是有一些差别。比如我考虑了几个方案:

  1. 重写目前的登录校验逻辑,不使用默认的admin模板的用户

  2. 复用已有的用户模型,然后添加几个定制字段来满足需求

根据目前的功能实现,如果重写user的模型,会有较大的难度,所以第一点可行但是代价太高,第二点的考虑是用户的密码校验一个是默认实现的逻辑,代码改动后会不稳定而且改动效率较低,因为原来的用户是一个抽象类,需要重新改动,代价也不低。

所以,思来想去,怎么做都代价不小,于是乎,换了一个思路。原来的逻辑是静态的,根据提供的菜单列表来得到一些可选的权限,我们可以保留这个逻辑,重新定制一下菜单的部分,菜单和用户为多对多的关系,原来的用户表也不用改动,只需要定制关系表就可以了。

所以权衡再三的想法是如果没权限就不要直接看到菜单,这部分的关系在多对多的映射中体现。

到了这个程度,其实就离具体实现不远了,我们继续来理一下。

系统中默认创建的用户只有普通权限,需要登录到系统激活才可以使用,所以我们的系统的想法是不要求一步到位,类似于邀请制,指定的用户才可以配置相应的权限,所以不会出现一下子创建出来多个超级用户的情况,原来的逻辑就不用改动,继续保留。

在这个基础上配置一个菜单管理页面,把每个菜单的标题,url,映射信息都和用户映射起来。

前端显示的部分则通过首页的index.html根据用户的信息动态匹配得到一个较新的菜单列表,意味着每个人看到的菜单可能不同。

用户和菜单之间是多对多的关联关系

所以Django中的models.py的内容如下:

class Menu(models.Model):

menu_type_choices = (

( 'dashborad', u'平台看板') ,

( 'cmdb', u'资产管理') ,

( 'env_deploy', u'环境部署') ,

( 'backup', u'数据备份') ,

( 'recover', u'数据恢复') ,

( 'scheduler', u'任务调度') ,

( 'global_config', u'全局配置') ,

( 'user_center', u'用户中心') ,

)

server_status_choices = (

( '1', 'valid') ,

( '0', 'invalid') ,

)

menu_id = models.SmallIntegerField( primary_key= True,verbose_name= '菜单ID')

menu_title = models.CharField( max_length= 50,verbose_name= '菜单标题')

menu_url = models.CharField( max_length= 50,verbose_name= '菜单URL',unique= False)

menu_level = models.SmallIntegerField( blank= True,null= False,verbose_name= '菜单等级')

menu_parent_level = models.SmallIntegerField( blank= True,null= False,verbose_name= '菜单父等级')

menu_style = models.CharField( max_length= 50,verbose_name= '菜单选用的组件风格')

menu_type = models.CharField( max_length= 50,choices=menu_type_choices ,null= False,verbose_name= '菜单大类')

create_date = models.DateTimeField( auto_now_add= True)

update_date = models.DateTimeField( auto_now_add= True)

user_role = models.ManyToManyField(User)

menu_status = models.SmallIntegerField( choices=server_status_choices ,null= False,verbose_name= '菜单状态')

class Meta:

db_table = 'menu'

permissions = (

( "can_read_menu", "读取菜单权限") ,

( "can_change_menu", "更改菜单权限") ,

( "can_add_menu", "添加菜单权限") ,

( "can_delete_menu", "删除菜单权限") ,

)

verbose_name = '菜单配置'

verbose_name_plural = '菜单配置'

ORM映射生成的SQL类似下面的形式:

BEGIN;

CREATE TABLE `menu` (`menu_id` smallint NOT NULL PRIMARY KEY , `menu_title` varchar( 50) NOT NULL , `menu_url` varchar( 50) NOT NULL , `menu_level` smallint NULL , `menu_parent_level` smallint NULL , `menu_style` varchar( 50) NOT NULL , `menu_type` smallint NOT NULL , `create_date` datetime( 6) NOT NULL , `update_date` datetime( 6) NOT NULL , `menu_status` smallint NOT NULL);

CREATE TABLE `menu_user_role` (` id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY , `menu_id` smallint NOT NULL , `user_id` integer NOT NULL , UNIQUE (`menu_id` , `user_id`));

ALTER TABLE `menu_user_role` ADD CONSTRAINT `menu_user_role_menu_id_15dc921823a77a3f_fk_menu_menu_id` FOREIGN KEY (`menu_id`) REFERENCES `menu` (`menu_id`);

ALTER TABLE `menu_user_role` ADD CONSTRAINT `menu_user_role_user_id_52439a830d70516d_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (` id`);

COMMIT;

有了这些基本的设计,我们来模拟测试一下,当前的menu为空。

>>> from django.contrib.auth.models import User

>>> from db_ops.models import Menu

>>> Menu.objects.all()

( 0.001) QUERY = u'SELECT "menu"."menu_id", "menu"."menu_title", "menu"."menu_url", "menu"."menu_level", "menu"."menu_parent_level", "menu"."menu_style", "menu"."menu_type", "menu"."create_date", "me

nu "."update_date ", "menu "."menu_status " FROM "menu " LIMIT 21' - PARAMS = (); args=()

[]

我们调用API生成一个user,一个menu信息。

User.objects.create(password= 'admin2',is_superuser= 0,username= 'admin2',first_name= 'admin',last_name= 'admin',email= 'aa@aa.com',is_staff= 0,is_active= 1,date_joined= '2018-01-04')

Menu.objects.create( menu_id= 1,menu_title= '元数据管理',menu_url= 'cmdb_manage',menu_level= 2,menu_parent_level= 1,menu_type= 'cmdb',create_date= '2018-01-04',update_date= '2018-01-04',menu_status= 1)

如果要做多对多的映射,则是使用add方法,注意生成的insert语句。

user = User.objects.get( pk= 2)

menu = Menu.objects.get( pk= 1) >>> menu.user_role.add(user)

( 0.000) QUERY = u'BEGIN' - PARAMS = (); args= None

( 0.000) QUERY = u'SELECT "menu_user_role"."user_id" FROM "menu_user_role" WHERE ("menu_user_role"."menu_id" = %s AND "menu_user_role"."user_id" IN (%s))' - PARAMS = ( 1, 2); args=( 1, 2)

( 0.081) QUERY = u'INSERT INTO "menu_user_role" ("menu_id", "user_id") SELECT %s AS "menu_id", %s AS "user_id"' - PARAMS = ( 1, 2); args=( 1, 2)

如果要查询中间表的数据,可以做关联,比如下面的形式。

>>>User.objects.filter( menu__user_role= 1)

后续继续补充完善。

上一篇: Python之Numpy初识
请登录后发表评论 登录
全部评论

注册时间:2012-05-14

  • 博文量
    1499
  • 访问量
    14154972