做Web的大部分都有一个后台用于管理一些数据的增删改查,而Django 内置了一个权限系统。它提供了为指定的用户和用户组分配权限的方法。它在 Django 管理后台界面里使用,但你也可以在自己的代码中使用它。(图网上找的,django内置的权限差不多就是这样的)
1、创建一个Django项目:
django-admin startproject 工程名称
2、创建子应用:
python manage.py startapp 子应用名称
创建完子应用需要注册的要不然模型类迁移不会成功
以下就在demo2中演示。
3、创建模型类:
在demo2中新建了一个models.py用于写模型类对象内容如下:
from django.contrib.auth.models import AbstractUser
from django.db import models
# Create your models here.
class User(AbstractUser):
"""用户模型类
创建自定义的用户模型类
Django认证系统中提供的用户模型类及方法很方便,我们可以使用这个模型类,但是字段有些无法满足项目需求,如本项目中需要保存用户的手机号,
需要给模型类添加额外的字段。
Django提供了django.contrib.auth.models.AbstractUser用户抽象模型类允许我们继承,扩展字段来使用Django认证系统的用户模型类。
我们自定义的用户模型类还不能直接被Django的认证系统所识别,需要在配置文件中告知Django认证系统使用我们自定义的模型类。
在配置文件中进行设置
AUTH_USER_MODEL = 'users.User'
AUTH_USER_MODEL 参数的设置以点.来分隔,表示应用名.模型类名。
"""
mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
class Meta:
db_table = 'tb_users'
verbose_name = '用户'
verbose_name_plural = verbose_name
# 定义图书模型类BookInfo
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, wverbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期')
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_books' # 指明数据库表名
verbose_name = '图书' # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称```
def __str__(self):
"""定义每个数据对象的显示信息"""
return self.btitle
# 定义英雄模型类HeroInfo
class HeroInfo(models.Model):
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
hname = models.CharField(max_length=20, verbose_name='名称')
hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_heros'
verbose_name = '英雄'
verbose_name_plural = verbose_name
def __str__(self):
return self.hname
我定义了三个模型类分别是User、BooInfo、HeroInfo
4、进行迁移
将模型类同步到数据库中。
1、生成迁移文件
python manage.py makemigrations
2、同步到数据库中
python manage.py migrate
5、数据库中自动生成的表
Django用permission对象存储权限项,每个model默认都有四个permission,即add model, change model和delete model。例如,定义一个名为学生BookInfo模型,当迁移表后,会在auth_permission中自动创建相应的三个permission:add_bookinfo, change_bookinfo,view_bookinfo和delete_bookinfo。Django还允许自定义permission。
我例子中用的是默认的懒得写,下面就大概说说:
6、自定义权限
自定义权限(一)
在自定义模型的Meta元中添加permissions参数,自定义权限的名称(‘codename’,‘name’)即codename为权限名,name为权限的描述。在数据库的auth_permission表中还有一个content_type字段,其表示prmission属于哪个model
如何取消默认权限?
class Blog(models.Model):
.....
class Meta:
default_permissions = ()
.......
default_permissions: 清空默认的权限
注意:如果你使用了django默认的admin的话,建议保留4个默认权限,可以添加新权限
class User(AbstractUser):
mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
class Meta:
permissions = (
('add_user_per', '添加用户权限'),
('del_user_per', '删除用户权限'),
('change_user_per', '修改用户权限'),
('sel_user_per', '查询用户权限')
)
db_table = 'tb_users'
verbose_name = '用户'
verbose_name_plural = verbose_name
注意:在数据库的auth_permission表中,会新增权限,包括自带的对Users管理的权限,和自定义的四个权限。
自定义权限(二)
在业务逻辑中创建权限,则可以通过Permission模型来创建权限
def add_user_permission(request):
if request.method == 'GET':
# 获取当前Users模型的id值
content_type = ContentType.objects.get_for_model(User)
# codename为权限名,name为描述,content_type为当前权限属于哪一个模型的ID
Permission.objects.create(
codename='add_other_user_permission',
name='添加其他用户权限',
content_type=content_type
)
return HttpResponse('创建权限成功')
7、分配权限
(1)给用户直接添加某种权限
采用直接分配权限的方法,给用户添加额外的权限既用户表User和权限Permission模型以及中间表user_permission之间的关联关系。用户User模型和权限Permission之间是ManyToManyField()多对多关联关系,关联字段为user_permission。
语法:
添加权限:user对象.user_permission.add(permission对象1, permission对象2)
删除权限:user对象.user_permission.remove(permission对象1, permission对象2)
清空权限:user对象.user_permission.clear()
(2)创建组并分配对应组的权限
语法:
给组添加权限,涉及到组group表和permission权限表,以及中间关联表。其为ManyToManyFiled()关联关系,关联字段为permissions 语法:
添加权限:group对象.permissions.add(permission对象1, permission对象2)
删除权限:group对象.permissions.remove(permission对象1, permission对象2)
清空权限:group对象.permissions.clear()
(3)分配用户和权限组
给用户添加组权限,涉及到组group表和user用户表,以及中间关联表。其为ManyToManyFiled()关联关系,关联字段为groups 语法:
添加权限:user对象.groups.add(groups对象1, groups对象2)
删除权限:user对象.groups.remove(groups对象1, groups对象2)
清空权限:user对象.groups.clear()
示例如下:
from django.views.generic import View
from demo2.models import User
from django.contrib.auth.models import Permission, Group
from django.http import HttpResponse
# 添加权限
class AddQx(View):
def get(self, request):
user_id = request.GET.get('user_id', 1)
pres_list = request.GET.getlist('pres')
pres_str = pres_list[0].split(',')
user = User.objects.get(id=user_id)
pres = Permission.objects.filter(codename__in=pres_str)
print(pres)
for pre in pres:
user.user_permissions.add(pre)
return HttpResponse('添加权限成功')
# 修改权限
class ChangeQx(View):
def get(self, request):
user_id = int(request.GET.get('user_id', '1'))
pres_list = request.GET.getlist('pres')
pres_str = pres_list[0].split(',')
user = User.objects.get(id=user_id)
# 修改权限先清空权限,在添加
user.user_permissions.clear()
user.user_permissions.add(pres_str)
return HttpResponse('修改权限成功')
# 删除权限
class DeleteQx(View):
def get(self, request):
user_id = int(request.GET.get('user_id', '1'))
pres_list = request.GET.getlist('pres')
pres_str = pres_list[0].split(',')
pres = Permission.objects.filter(codename__in=pres_str)
user = User.objects.get(id=user_id)
user.user_permissions.remove(pres)
return HttpResponse('删除权限成功')
# 查看权限
class ViewQx(View):
def get(self, request):
user_id = int(request.GET.get('user_id', '1'))
user = User.objects.get(id=user_id)
all_per = user.get_all_permissions()
if user.has_perms(['demo2.add_bookinfo']):
print('用户具有添加书籍的权限')
return HttpResponse(all_per)
# 创建组
class AddGroup(View):
def get(self, requset):
name = requset.GET.get('name', 'xxx')
try:
group = Group(
name=name
)
group.save()
return HttpResponse('创建组成功')
except:
return HttpResponse('创建组失败')
# 添加组权限
class AddGroupQx(View):
def get(self, requset):
ser_id = int(requset.GET.get('user_id', '1'))
super_group = Group.objects.get(id=8)
pers = Permission.objects.filter(codename__in=[
'add_bookinfo',
'change_bookinfo',
'delete_bookinfo',
'view_bookinfo'])
for per in pers:
# 添加超级用户组的权限
super_group.permissions.add(per)
# # 删除超级组的权限
# super_group.permissions.remove(per)
# # 清空组的权限
# super_group.permissions.clear()
return HttpResponse('创建组权限')
# 分配用户权限组
class UserGroup(View):
def get(self, request):
# 给id为1的用户分配组的权限
# 获取超级管理员组group对象
super_group = Group.objects.get(name='xxx')
# 获取id=1d的用户对象
user = User.objects.get(id=1)
# 添加超级用户组的权限
user.groups.add(super_group)
# 删除超级组的权限
# user.groups.remove(super_group)
# 清空组的权限
# user.groups.clear()
return HttpResponse('创建用户组权限')
8、检测权限
(1)使用has_perm方法:
语法:
用户对象.has_perm('应用名.权限codename')
查询用户所有的权限:user.get_all_permissions()方法列出用户的所有权限,返回值是permission name
查询用户的组权限:user.get_group_permissions()方法列出用户所属group的权限,返回值是permission name
class JaoYan(View):
def get(self, request):
# 获取id=1d的用户对象
user = User.objects.get(id=1)
# 查看用户的所有权限
all_perm = user.get_all_permissions()
# 查看用户的组权限
group_perm = user.get_group_permissions()
# 查询用户是否有add_user_per权限
if user.has_perm('demo2.change_bookinfo'):
return HttpResponse('用户有delete_bookinfo权限')
else:
return HttpResponse('用户没有delete_bookinfo权限')
user.has_perm('demo2.change_bookinfo')会返回布尔类型
(2)使用permission_required装饰器
语法:@permission_required('应用app名.权限名codename')
源代码:
def permission_required(perm, login_url=None, raise_exception=False):
"""
视图的装饰器,用于检查用户是否已启用特定权限,并在必要时重定向到登录页面。如果给了
raise_exception参数,则会引发PermissionDenied异常
"""
def check_perms(user):
if isinstance(perm, str):
perms = (perm,)
else:
perms = perm
# First check if the user has the permission (even anon users)
if user.has_perms(perms):
return True
# In case the 403 handler should be called raise the exception
if raise_exception:
raise PermissionDenied
# As the last resort, show the login form
return False
return user_passes_test(check_perms, login_url=login_url)
permission_required有三个参数:
perm:描述权限的字符串,格式为:app名.权限。如"auth.add_user",“auth.delete_user”
login_url:如果没有权限需要跳转的url字符串,如"/login",“https://www.baidu.com”
raise_exception:boolean值,没有权限是否触发PermissionDenied异常,触发异常则直接返回,不会跳转到login_url
示例:
class UserGroup(View):
@method_decorator(permission_required('demo2.view_bookinfo', raise_exception=True))
def get(self, request):
# 给id为1的用户分配超级管理员组的权限
# 获取超级管理员组group对象
super_group = Group.objects.get(name='xxx')
# 获取id=1d的用户对象
user = User.objects.get(id=1)
# 添加超级用户组的权限
user.groups.add(super_group)
return HttpResponse('创建用户组权限')
Django权限最小的粒度是表,如果需要更小的粒度需要Django-guardian
pip install django-guardian