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使用内存zipfile对象在内存中打包文件示例
Apr 30 Python
Python中的super()方法使用简介
Aug 14 Python
总结python实现父类调用两种方法的不同
Jan 15 Python
Python使用matplotlib绘制多个图形单独显示的方法示例
Mar 14 Python
关于Python 的简单栅格图像边界提取方法
Jul 05 Python
Pandas中DataFrame的分组/分割/合并的实现
Jul 16 Python
解决Django删除migrations文件夹中的文件后出现的异常问题
Aug 31 Python
Tensorflow 1.0之后模型文件、权重数值的读取方式
Feb 12 Python
Python实现扫码工具的示例代码
Oct 09 Python
django中cookiecutter的使用教程
Dec 03 Python
python 如何执行控制台命令与操作剪切板
May 20 Python
Python实现8种常用抽样方法
Jun 27 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 mysql 判断update之后是否更新了的方法
2012/01/10 PHP
PHP借助phpmailer发送邮件
2015/05/11 PHP
PHP设计模式之适配器模式代码实例
2015/05/11 PHP
Javascript操作select方法大全[新增、修改、删除、选中、清空、判断存在等]
2008/09/26 Javascript
关于URL中的特殊符号使用介绍
2011/11/03 Javascript
jQuery 获取和设置select下拉框的值实现代码
2013/11/08 Javascript
Jquery中children与find之间的区别详细解析
2013/11/29 Javascript
jquery实现的鼠标拖动排序Li或Table
2014/05/04 Javascript
使用AmplifyJS组件配合JavaScript进行编程的指南
2015/07/28 Javascript
JavaScript通过使用onerror设置默认图像显示代替alt
2016/03/01 Javascript
url传递的参数值中包含&amp;时,url自动截断问题的解决方法
2016/08/02 Javascript
基于MVC+EasyUI的web开发框架之使用云打印控件C-Lodop打印页面或套打报关运单信息
2016/08/29 Javascript
Javascript下拉刷新的简单实现
2017/02/14 Javascript
javascript如何使用函数random来实现课堂随机点名方法详解
2020/07/28 Javascript
[33:17]OG vs VGJ.T 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python实现把xml或xsl转换为html格式
2015/04/08 Python
在Python中使用模块的教程
2015/04/27 Python
使用python爬虫实现网络股票信息爬取的demo
2018/01/05 Python
python中的decorator的作用详解
2018/07/26 Python
python+PyQT实现系统桌面时钟
2020/06/16 Python
详解利用python+opencv识别图片中的圆形(霍夫变换)
2019/07/01 Python
Python 函数用法简单示例【定义、参数、返回值、函数嵌套】
2019/09/20 Python
解决Pytorch 加载训练好的模型 遇到的error问题
2020/01/10 Python
解决更改AUTH_USER_MODEL后出现的问题
2020/05/14 Python
在pytorch中动态调整优化器的学习率方式
2020/06/24 Python
Hawes & Curtis澳大利亚官网:英国经典服饰品牌
2018/10/29 全球购物
苹果台湾官网:Apple台湾
2019/01/05 全球购物
旅游与酒店管理的自我评价分享
2013/11/03 职场文书
财务部出纳岗位职责
2013/12/22 职场文书
同学会邀请书大全
2014/01/12 职场文书
学校远程教育工作总结
2015/08/11 职场文书
最美劳动诗,致敬所有的劳动者!
2019/07/12 职场文书
酒店工程部的岗位职责汇总大全
2019/10/23 职场文书
实习员工转正的评语汇总,以备不时之需
2019/12/17 职场文书
python基础之停用词过滤详解
2021/04/21 Python
golang如何去除多余空白字符(含制表符)
2021/04/25 Golang