Django 权限管理(permissions)与用户组(group)详解


Posted in Python onNovember 30, 2020

如果你只是利用Django开发个博客,大部分用户只是阅读你的文章而已,你可能根本用不到本节内容。但是如果你想开发一个内容管理系统,或用户管理系统,你必需对用户的权限进行管理和控制。Django自带的权限机制(permissions)与用户组(group)可以让我们很方便地对用户权限进行管理。小编我今天就尝试以浅显的语言来讲解下如何使用Django自带的权限管理机制。

什么是权限?

权限是能够约束用户行为和控制页面显示内容的一种机制。一个完整的权限应该包含3个要素: 用户,对象和权限,即什么用户对什么对象有什么样的权限。

假设我们有一个应用叫blog,其包含一个叫Article(文章)的模型。那么一个超级用户一般会有如下4种权限,而一个普通用户可能只有1种或某几种权限,比如只能查看文章,或者能查看和创建文章但是不能修改和删除。

  • 查看文章(view)
  • 创建文章(add)
  • 更改文章(change)
  • 删除文章(delete)

我们在Django的admin中是可以很轻易地给用户分配权限的。

Django Admin中的权限分配

Django中的用户权限分配,主要通过Django自带的Admin界面进行维护的。当你编辑某个user信息时, 你可以很轻易地在User permissions栏为其设置对某些模型查看, 增加、更改和删除的权限(如下图所示)。 

Django的权限permission本质是djang.contrib.auth中的一个模型, 其与User的user_permissions字段是多对多的关系。当我们在INSTALLED_APP里添加好auth应用之后,Django就会为每一个你安装的app中的模型(Model)自动创建4个可选的权限:view, add,change和delete。(注: Django 2.0前没有view权限)。随后你可以通过admin将这些权限分配给不同用户。

查看用户的权限

权限名一般有app名(app_label),权限动作和模型名组成。以blog应用为例,Django为Article模型自动创建的4个可选权限名分别为:

  • 查看文章(view): blog.view_article
  • 创建文章(add): blog.add_article
  • 更改文章(change): blog.change_article
  • 删除文章(delete): blog.delete_article

在前例中,我们已经通过Admin给用户A(user_A)分配了创建文章和修改文章的权限。我们现在可以使用user.has_perm()方法来判断用户是否已经拥有相应权限。下例中应该返回True。

  • user_A.has_perm('blog.add_article')
  • user_A.has_perm('blog.change_article')

如果我们要查看某个用户所在用户组的权限或某个用户的所有权限(包括从用户组获得的权限),我们可以使用get_group_permissions()和get_all_permissions()方法。

  • user_A.get_group_permissions()
  • user_A.get_all_permissions()

手动定义和分配权限(Permissions

有时django创建的4种可选权限满足不了我们的要求,这时我们需要自定义权限。实现方法主要有两种。下面我们将分别使用2种方法给Article模型新增了两个权限,一个是publish_article, 一个是comment_article。

方法1. 在Model的meta属性中添加permissions。

class Article(models.Model):
  ...
  class Meta:
    permissions = (
      ("publish_article", "Can publish article"),
      ("comment_article", "Can comment article"),
    )

方法2. 使用ContentType程序化创建permissions。

from blog.models import Article
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
 
content_type = ContentType.objects.get_for_model(article)
permission1 = Permission.objects.create(
  codename='publish_article',
  name='Can publish articles',
  content_type=content_type,
)
 
permission2 = Permission.objects.create(
  codename='comment_article',
  name='Can comment articles',
  content_type=content_type,
)

当你使用python manage.py migrate命令后,你会发现Django admin的user permissions栏又多了两个可选权限。

如果你不希望总是通过admin来给用户设置权限,你还可以在代码里手动给用户分配权限。这里也有两种实现方法。

方法1. 使用user.user_permissions.add()方法

myuser.user_permissions.add(permission1, permission2, ...)

方法2. 通过user所在的用户组(group)给用户增加权限

mygroup.permissions.add(permission1, permission2, ...)

如果你希望在代码中移除一个用户的权限,你可以使用remove或clear方法。

myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

注意权限的缓存机制

Django会缓存每个用户对象,包括其权限user_permissions。当你在代码中手动改变一个用户的权限后,你必须重新获取该用户对象,才能获取最新的权限。

比如下例在代码中给用户手动增加了change_blogpost的权限,如果不重新载入用户,那么将显示用户还是没有change_blogpost的权限。

from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404
 
from myapp.models import BlogPost
 
def user_gains_perms(request, user_id):
  user = get_object_or_404(User, pk=user_id)
  # any permission check will cache the current set of permissions
  user.has_perm('myapp.change_blogpost') 
 
  content_type = ContentType.objects.get_for_model(BlogPost)
  permission = Permission.objects.get(
    codename='change_blogpost',
    content_type=content_type,
  )
  user.user_permissions.add(permission)
 
  # Checking the cached permission set
  user.has_perm('myapp.change_blogpost') # False
 
  # Request new instance of User
  # Be aware that user.refresh_from_db() won't clear the cache.
  user = get_object_or_404(User, pk=user_id)
 
  # Permission cache is repopulated from the database
  user.has_perm('myapp.change_blogpost') # True

用户权限的验证(Validation)

我们前面讲解了用户权限的创建和设置,现在我们将进入关键一环,用户权限的验证。我们在分配好权限后,我们还需要在视图views.py和模板里验证用户是否具有相应的权限,否则前面设置的权限形同虚设。这就是为什么我们前面很多django实战案例里,没有给用户分配某个模型的add和change权限,用户还是还能创建和编辑对象的原因。

1. 视图中验证

在视图中你当然可以使用user.has_perm方法对一个用户的权限进行直接验证。当然一个更好的方法是使用@permission_required这个装饰器。

permission_required(perm, login_url=None, raise_exception=False)

你如果指定了login_url, 用户会被要求先登录。如果你设置了raise_exception=True, 会直接返回403无权限的错误,而不会跳转到登录页面。使用方法如下所示:

from django.contrib.auth.decorators import permission_required
 
@permission_required('polls.can_vote')
def my_view(request):
  ...

如果你使用基于类的视图(Class Based View), 而不是函数视图,你需要继承PermissionRequiredMixin这个类,如下所示:

from django.contrib.auth.mixins import PermissionRequiredMixin
 
class MyView(PermissionRequiredMixin, View):
  permission_required = 'polls.can_vote'
  # Or multiple of permissions:
  permission_required = ('polls.can_open', 'polls.can_edit')

2. 模板中验证

在模板中验证用户权限主要需要学会使用perms这个全局变量。perms对当前用户的user.has_module_perms和user.has_perm方法进行了封装。当我们需要判断当前用户是否拥有blog应用下的所有权限时,我们可以使用:

{{ perms.blog }}

我们如果判断当前用户是否拥有blog应用下发表文章讨论的权限,则使用:

{{ perms.blog.comment_article }}

这样结合template的if标签,我们可以通过判断当前用户所具有的权限,显示不同的内容了.

{% if blog.article %}
  <p>You have permission to do something in this blog app.</p>
  {% if perms.blog.add_article %}
    <p>You can add articles.</p>
  {% endif %}
  {% if perms.blog.comment_article %}
    <p>You can comment articles!</p>
  {% endif %}
{% else %}
  <p>You don't have permission to do anything in the blog app.</p>
{% endif %}

用户组(Group)

 用户组(Group)和User模型是多对多的关系。其作用在权限控制时可以批量对用户的权限进行管理和分配,而不用一个一个用户分配,节省工作量。将一个用户加入到一个Group中后,该用户就拥有了该Group所分配的所有权限。例如,如果一个用户组editors有权限change_article, 那么所有属于editors组的用户都会有这个权限。

将用户添加到用户组或者给用户组(group)添加权限,一般建议直接通过django admin进行。如果你希望手动给group添加或删除权限,你可以使用如下方法。

mygroup.permissions = [permission_list]
mygroup.permissions.add(permission, permission, ...)
mygroup.permissions.remove(permission, permission, ...)
mygroup.permissions.clear()

如果你要将某个用户移除某个用户组,可以使用如下方法。

myuser.groups.remove(group, group, ...) #
myuser.groups.clear()

Django自带权限机制的不足

Django自带的权限机制是针对模型的,这就意味着一个用户如果对Article模型有change的权限,那么该用户获得对所有文章对象进行修改的权限。如果我们希望实现对单个文章对象的权限管理,我们需要借助于第三方库比如django guardian。至于该库的使用,我们以后再详细介绍。

到此这篇关于Django 权限管理(permissions)与用户组(group)详解的文章就介绍到这了,更多相关Django 权限管理与用户组内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python写的Discuz7.2版faq.php注入漏洞工具
Aug 06 Python
讲解Python中的递归函数
Apr 27 Python
在Python的Django框架中加载模版的方法
Jul 16 Python
python列表操作之extend和append的区别实例分析
Jul 28 Python
Python实现中一次读取多个值的方法
Apr 22 Python
pycharm重置设置,恢复默认设置的方法
Oct 22 Python
python pandas时序处理相关功能详解
Jul 03 Python
python爬虫 基于requests模块发起ajax的get请求实现解析
Aug 20 Python
Python 实现判断图片格式并转换,将转换的图像存到生成的文件夹中
Jan 13 Python
Tensorflow tf.dynamic_partition矩阵拆分示例(Python3)
Feb 07 Python
python使用gdal对shp读取,新建和更新的实例
Mar 10 Python
python matplotlib:plt.scatter() 大小和颜色参数详解
Apr 14 Python
python 如何引入协程和原理分析
Nov 30 #Python
Django缓存Cache使用详解
Nov 30 #Python
Django框架实现在线考试系统的示例代码
Nov 30 #Python
python爬虫 requests-html的使用
Nov 30 #Python
python实现登录与注册系统
Nov 30 #Python
python代码实现图书管理系统
Nov 30 #Python
python 爬虫网页登陆的简单实现
Nov 30 #Python
You might like
用PHP读取flv文件的播放时间长度
2009/09/03 PHP
php 按指定元素值去除数组元素的实现方法
2011/11/04 PHP
基于PHP编程注意事项的小结
2013/04/27 PHP
PHP实现四种基础排序算法的运行时间比较(推荐)
2016/08/11 PHP
js下获取div中的数据的原理分析
2010/04/07 Javascript
GreyBox技术总结(转)
2010/11/23 Javascript
jQuery创建插件的代码分析
2011/04/14 Javascript
JQuery调用绑定click事件的3种写法
2015/03/28 Javascript
jQuery实现点击小图显示大图代码分享
2015/08/25 Javascript
利用Vue.js实现求职在线之职位查询功能
2017/07/03 Javascript
angular.js4使用 RxJS 处理多个 Http 请求
2017/09/23 Javascript
利用jquery和BootStrap实现动态滚动条效果
2018/12/03 jQuery
详解Vue中的Props与Data细微差别
2020/03/02 Javascript
关于vue 结合原生js 解决echarts resize问题
2020/07/26 Javascript
Python中Collections模块的Counter容器类使用教程
2016/05/31 Python
详解Django rest_framework实现RESTful API
2018/05/24 Python
解读python如何实现决策树算法
2018/10/11 Python
django框架事务处理小结【ORM 事务及raw sql,customize sql 事务处理】
2019/06/27 Python
从列表或字典创建Pandas的DataFrame对象的方法
2019/07/06 Python
妙用itchat! python实现久坐提醒功能
2019/11/25 Python
python中从for循环延申到推导式的具体使用
2019/11/29 Python
怎样实现H5+CSS3手指滑动切换图片的示例代码
2019/05/05 HTML / CSS
美津浓巴西官方网站:Mizuno巴西
2019/07/24 全球购物
Farfetch巴西官网:奢侈品牌时尚购物平台
2020/10/19 全球购物
介绍一下Linux中的链接
2016/06/05 面试题
秋季运动会通讯稿
2014/01/24 职场文书
医务工作者先进事迹材料
2014/01/26 职场文书
英语一分钟演讲稿
2014/04/29 职场文书
2014年库房工作总结
2014/11/26 职场文书
2014年统战工作总结
2014/12/09 职场文书
预备党员表决心的话
2015/09/22 职场文书
美德少年事迹材料(2016推荐版)
2016/02/25 职场文书
导游词之张家界
2019/10/31 职场文书
css中z-index: 0和z-index: auto的区别
2021/08/23 HTML / CSS
python读取并查看npz/npy文件数据以及数据显示方法
2022/04/14 Python
一篇文章带你掌握SQLite3基本用法
2022/06/14 数据库