使用django-guardian实现django-admin的行级权限控制的方法


Posted in Python onOctober 30, 2018

用django框架来做一些后台管理的web页面简直太方便了,django自带模块级的权限系统,用来做一些内部的系统非常合适,可以大大的减少开发量。但是django自带的权限系统还不支持行级的权限控制,如果要实现行级的权限控制,需要依赖第三方的app来开发,或者自己重新写一个。

需求描述

我们项目组开发的一些系统通常会用mysql数据库来存储一些配置,但是如果每次有配置修改的时候都去手动修改mysql数据的话,会挺麻烦的,同时也比较容易出错。django-admin能够根据定义的model自动的生成相应的页面,同时还能提供权限的管理,所以我们就把一些系统到的配置放到django中。但是到现在,随着系统的需求越来越多,该系统已经不止我们自己项目组的人员使用,也要开放给其他项目组的同事使用,所以就产生了一些更细粒度的权限需求。因此,我们要在现有的系统上支持行级的权限控制。

解决方案

当然可以自己写一套权限系统了,但是自己写的成本比较高,而且自己写的不一定比较好。所以我就先在网上找了一些现成的解决方案, https://djangopackages.org/grids/g/perms/ 该链接列出了现有的一些第三方的权限系统解决方案。从该页面来看,django-guardian是最受欢迎的第三方权限系统,而且支持行级的权限系统,同时还可以整合到django-admin里面,所以我就选择了django-guardian。

关键步骤

安装配置django-guardian

安装配置django-guardian比较简单,按照她项目提供的 文档 进行安装就可以了,安装完成后会在数据库里面创建两张权限相关的表。

把django-guardian整合到django-admin

首先把admin.py文件里面需要用到行级权限的类,由原来的继承admin.ModelAdmin,改成继承GuardedModelAdmin,这时候打开某个数据行的页面的时候,在该页面的右上角的历史旁边会显示编辑对象权限的按钮,点击该按钮进去相应的页面就可以编辑该行数据的具体权限。

配置完权限的时候,用一个新的用户测试的话,会发现该用户没有权限来访问任何的数据,这是因为GuardedModelAdmin还有很多事情没有帮我们做,我们还需要重写一些函数来实现admin后台页面的显示。具体的信息看下面的代码注释。

from guardian.admin import GuardedModelAdmin
from guardian.shortcuts import get_objects_for_user, assign_perm, remove_perm, get_users_with_perms, \
  get_groups_with_perms
  
# 需改前
@admin.register(DataAssistantJob)
class DataAssistantJobAdmin(admin.ModelAdmin):
  pass

# 修改后
@admin.register(DataAssistantJob)
class DataAssistantJobAdmin(GuardedModelAdmin):
  # app是否在主页面中显示的话由该函数决定
  def has_module_permission(self, request):
    if super().has_module_permission(request):
      return True
    return self.get_model_objs(request).exists()

  # 在显示数据列表额时候,哪些数据显示,哪些不显示,由该函数控制
  def get_queryset(self, request):
    if request.user.is_superuser:
      return super().get_queryset(request)

    data = self.get_model_objs(request)
    return data
    
  # 内部用来获取某个用户有权限访问的数据行
  def get_model_objs(self, request, action=None, klass=None):
    opts = self.opts
    actions = [action] if action else ['view', 'change', 'delete']
    klass = klass if klass else opts.model
    model_name = klass._meta.model_name
    return get_objects_for_user(user=request.user, perms=[f'{perm}_{model_name}' for perm in actions],
                  klass=klass, any_perm=True)

  # 用来判断某个用户是否有某个数据行的权限
  def has_perm(self, request, obj, action):
    opts = self.opts
    codename = f'{action}_{opts.model_name}'
    if obj:
      return request.user.has_perm(f'{opts.app_label}.{codename}', obj)
    else:
      return self.get_model_objs(request, action).exists()

  # 是否有查看某个数据行的权限
  def has_view_permission(self, request, obj=None):
    return self.has_perm(request, obj, 'view')

  # 是否有修改某个数据行的权限
  def has_change_permission(self, request, obj=None):
    return self.has_perm(request, obj, 'change')

  # 是否有删除某个数据行的权限
  def has_delete_permission(self, request, obj=None):
    return self.has_perm(request, obj, 'delete')

  # 用户应该拥有他新增的数据行的所有权限
  def save_model(self, request, obj, form, change):
    result = super().save_model(request, obj, form, change)
    if not request.user.is_superuser and not change:
      opts = self.opts
      actions = ['view', 'add', 'change', 'delete']
      [assign_perm(f'{opts.app_label}.{action}_{opts.model_name}', request.user, obj) for action in actions]
    return result

通过上面的修改,django-admin中的模块就能够支持行级的权限,并能够正确的在后台页面中显示出来,当然如果有很多的模块需要支持行级的权限控制,则可以把上面的这些修改写到一个新的类中,然后其他想支持行级权限的模块再从该模块继承就可以了。

总结

感觉django-guardian和django-admin整合,实现的不是很好。如果开发者对django内部的代码不怎么了解,那么用django-guardian来实现行级权限控制的话会挺麻烦的,个人认为django-guardian完全可以把和django-admin的整合做到开箱即用的效果,就像django自带的权限系统一样。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中使用异常处理来判断运行的操作系统平台方法
Jan 22 Python
Python读写文件方法总结
Jun 09 Python
python-opencv 将连续图片写成视频格式的方法
Jan 08 Python
Python 3.6 -win64环境安装PIL模块的教程
Jun 20 Python
Python使用numpy模块实现矩阵和列表的连接操作方法
Jun 26 Python
pyqt5、qtdesigner安装和环境设置教程
Sep 25 Python
Python3 把一个列表按指定数目分成多个列表的方式
Dec 25 Python
python3+opencv 使用灰度直方图来判断图片的亮暗操作
Jun 02 Python
Python猫眼电影最近上映的电影票房信息
Sep 18 Python
Python爬虫之Selenium下拉框处理的实现
Dec 04 Python
python 实现体质指数BMI计算
May 26 Python
Python 居然可以在 Excel 中画画你知道吗
Feb 15 Python
解决Shell执行python文件,传参空格引起的问题
Oct 30 #Python
Python格式化输出字符串方法小结【%与format】
Oct 29 #Python
[原创]Python入门教程2. 字符串基本操作【运算、格式化输出、常用函数】
Oct 29 #Python
pycharm执行python时,填写参数的方法
Oct 29 #Python
解决Pycharm下面出现No R interpreter defined的问题
Oct 29 #Python
解决Pycharm运行时找不到文件的问题
Oct 29 #Python
解决Mac下首次安装pycharm无project interpreter的问题
Oct 29 #Python
You might like
php笔记之常用文件操作
2010/10/12 PHP
PHP多例模式介绍
2013/06/24 PHP
PHP中迭代器的简单实现及Yii框架中的迭代器实现方法示例
2020/04/26 PHP
JS获取父节点方法
2009/08/20 Javascript
JQuery 图片延迟加载并等比缩放插件
2009/11/09 Javascript
Web 前端设计模式--Dom重构 提高显示性能
2010/10/22 Javascript
javascript中onmouse事件在div中失效问题的解决方法
2012/01/09 Javascript
JavaScript中的noscript元素属性位置及作用介绍
2013/04/11 Javascript
js操作数组函数实例小结
2015/12/10 Javascript
jquery实现树形菜单完整代码
2015/12/29 Javascript
javascript中利用柯里化函数实现bind方法
2016/04/29 Javascript
bootstrap treeview 扩展addNode方法动态添加子节点的方法
2017/11/21 Javascript
解析Json字符串的三种方法日常常用
2018/05/02 Javascript
js实现简单的秒表
2020/01/16 Javascript
解决Mint-ui 框架Popup和Datetime Picker组件滚动穿透的问题
2020/11/04 Javascript
[01:04:02]DOTA2-DPC中国联赛 正赛 Elephant vs IG BO3 第二场 1月24日
2021/03/11 DOTA
Python Matplotlib库入门指南
2015/05/18 Python
Python 实现取矩阵的部分列,保存为一个新的矩阵方法
2018/11/14 Python
Python常用模块logging——日志输出功能(示例代码)
2019/11/20 Python
python3实现弹弹球小游戏
2019/11/25 Python
python3 动态模块导入与全局变量使用实例
2019/12/22 Python
关于Pytorch MaxUnpool2d中size操作方式
2020/01/03 Python
详解python os.path.exists判断文件或文件夹是否存在
2020/11/16 Python
检测浏览器对HTML5和CSS3支持度的方法
2015/06/25 HTML / CSS
Ray-Ban雷朋美国官网:全球领先的太阳眼镜品牌
2016/07/20 全球购物
XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式?
2016/01/12 面试题
公司财务工作总结的自我评价
2013/11/23 职场文书
大学毕业生个人自荐信范文
2014/01/08 职场文书
元旦联欢会感言
2014/03/04 职场文书
培训班开班仪式主持词
2014/03/28 职场文书
党员“四风”方面存在问题及整改措施
2014/09/24 职场文书
业务内勤岗位职责
2015/04/13 职场文书
保姆聘用合同
2015/09/21 职场文书
javascript canvas实现雨滴效果
2021/06/09 Javascript
Python必备技巧之字符数据操作详解
2022/03/23 Python
如何在Python中妥善使用进度条详解
2022/04/05 Python