玩转Django2.0---Django笔记建站基础九(二)

9.4  设置用户权限

  用户权限主要是对不同的用户设置不同的功能使用权限,而每个功能主要以模型来划分。以9.3节的MyDjango项目为例,在Admin后台管理系统可以查看并设置用户权限,如下图:

 

 用户权限设置

  上图左边列表框中列出了整个项目的用户权限,以user|用户|Can add user为例:

    1、user代表项目的App。

    2、用户代表App所定义的模型MyUser。

    3、Can add user代表该权限可对模型MyUser执行新增操作。

  一般情况下,在执行数据迁移时,每个模型默认拥有增(add), 改(change),删(delete)权限。数据迁移完成后,可以在数据库中查看数据表auth_permission的数据信息,每条数据信息代表项目中某个模型的某个权限,如下图:

 

   设置用户权限实质上是对数据表user_myuser和auth_permission之间的数据设置多对多关系。首先需要了解用户、用户权限和用户组三者之间的关系,以MyDjango的数据表为例,如下图:

 

   从整个项目的数据表可以看到,用户、用户权限和用户组分别对应数据表user_myuser、auth_permission和auth_group。无论是设置用户权限、设置用户所属用户组还是设置用户组的权限,其实质都是对两个数据表之间的数据建立多对多的数据关系,说明如下:

     1、数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,实现用户权限设置。

    2、数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,实现在用户组设置用户。

    3、数据表auth_group_permissions:管理数据表auth_group和auth_permission之间的多对多关系,实现用户组设置权限。

  实现用户的权限设置需要注意:如贵哦用户角色是超级用户,该用户是无须设置权限的,用户权限只适用于非超级用户。我们在PyCharm的Terminal下开启Django的shell模式来实现用户权限设置,代码如下:

(py3_3) E:\test5\MyDjango>python manage.py shell

#导入模型MyUser
In [1]: from user.models import MyUser
#查询用户信息,filter查询返回列表格式,因此设置列表索引获取User对象
In [3]: user = MyUser.objects.filter(username='user1')[0]
#判断当前用户是否具有权限add_product
#index.add_product为固定写法,index为项目的App名,add_product是数据表auth_permission的字段codename
In [4]: user.has_perm('index.add_product')
Out[4]: False

#导入模型Permission
In [5]: from django.contrib.auth.models import Permission

#在权限管理表获取权限add_product的数据对象permission
In [7]: permission = Permission.objects.filter(codename='add_product')[0]

#对当前用户对象user设置权限add_product
In [10]: user.user_permissions.add(permission)

#再次判断当前用户是否具有权限add_product
In [12]: user.has_perm('index.add_product')
Out[12]: True

  上述代码对用户名为user1的用户设置了产品信息的新增权限,打开数据表user_myuser_user_permissions可以看到新增了一条数据,如下图:

 

数据表user_myuser_user_permissions

  数据表的字段myuser_id和permission_id分别是数据表user_myuser和auth_permission的主键,如上图上的每一条数据代表某个用户具有某个模型的某个操作权限。除了添加权限之外,还可以对用户的权限进行删除和查询,代码如下:

In [6]: user = MyUser.objects.filter(username='user1')[0]

In [10]: permission = Permission.objects.filter(codename='add_product')[0]

#删除某条权限
In [11]: user.user_permissions.remove(permission)
#判断是否已删除权限,若为False,说明删除成功。函数has_perm用于判断用户是否拥有权限
In [12]: user.has_perm('index.add_product')
Out[12]: False

#清空当前用户全部权限
In [13]: user.user_permissions.clear()

#获取当前用户所拥有的权限信息
#将上述删除的权限添加到数据表再查询
In [14]: user.user_permissions.add(permission)

In [15]: user.user_permissions.values()
Out[15]: <QuerySet [{'id': 25, 'name': 'Can add product', 'content_type_id': 7, 'codename': 'add_product'}]>

 

9.5  自定义用户权限

 

  一般情况下,每个模型默认拥有增(add),改(change),删(delete)权限。但实际开发中,可能要对某个模型设置特殊的权限,比如设置访问权限。为了解决这种情况,在定义模型的时候,可以在模型的Meta中设置自定义权限。以MyDjango为例,对index的模型Product重新定义,代码如下:

#index/models.py
class Product(models.Model):
    id = models.AutoField('序号', primary_key=True)
    name = models.CharField('名称',max_length=50)
    weight = models.CharField('重量',max_length=20)
    size = models.CharField('尺寸',max_length=20)
    type = models.ForeignKey(Type, on_delete=models.CASCADE,verbose_name='产品类型')
    # 设置返回值
    def __str__(self):
        return self.name

    class Meta:
        #自定义权限
        permissions = (
            ('visit_Product', 'Can visit Product'),
        )

  定义模型Product的时候,通过重写父类models.Model的permissions属性可实现自定义用户权限。该属性以元组或列表的数据格式表示,每个元素代表一个权限,也是以元组或列表表示。在一个权限中含有两个元素,如('add_Product', 'Can create Product'),add_product和Can create Product分别是数据表auth_permission的codename和name字段。

  在数据库中清除MyDjango原有的数据表,并在PyCharm的Terminal中重新执行数据迁移,指令代码如下:

(py3_3) E:\test5\MyDjango>python manage.py makemigrations

(py3_3) E:\test5\MyDjango>python manage.py migrate

  指令执行完成后,在数据库中打开数据表auth_permission,可以找到自定义权限visit_Product,如下图:

 

自定义全visit_Product截图

 

9.6  设置网页的访问权限

 

  本节中,结合实际的例子讲述如何在实际开发中使用用户权限,以MyDjango为例,数据表auth_permission已自定义权限visit_Product,数据表user_myuser分别创建了一名超级用户和一名普通用户,如下图:

 

数据表user_myuser的用户信息

  本例需要将项目的index和user结合使用。index主要将权限应用到开发中,而user主要用于用户的注册、登录和退出登录,用于检验index的应用效果。

  首先讲解user的开发流程,我们分别对路由urls.py、视图views.py和模板user.html进行相应开发,共同完成用户的注册、登录和退出登录,代码如下:

#路由user/urls.py
from django.urls import path
from . import views


urlpatterns = [
    #用户登录
    path('login.html', views.loginView, name='login'),
    #用户注册
    path('register.html', views.registerView, name='register'),

    #退出登录
    path('logout.html', views.logoutView, name='logout'),
]


#视图user/views.py
from django.shortcuts import render, redirect
from .models import MyUser
from django.contrib.auth.models import Permission
from django.contrib.auth import login, authenticate, logout

# 用户登录
def loginView(request):
    tips = '请登录'
    title = '用户登录'
    if request.method == 'POST':
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        if MyUser.objects.filter(username=username):
            user = authenticate(username=username, password=password)
            if user:
                if user.is_active:
                    # 登录当前用户
                    login(request, user)
                return redirect('/')
            else:
                tips = '账号密码错误,请重新输入'
        else:
            tips = '用户不存在,请注册'
    return render(request, 'user.html', locals())

# 用户注册
def registerView(request):
    title = '用户注册'
    if request.method == 'POST':
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        if MyUser.objects.filter(username=username):
            tips = '用户已存在'
        else:
            user = MyUser.objects.create_user(username=username, password=password)
            user.save()
            # 添加权限
            permission = Permission.objects.filter(codename='visit_Product')[0]
            user.user_permissions.add(permission)
            return redirect('/user/login.html')
    return render(request, 'user.html', locals())

# 退出登录
def logoutView(request):
    logout(request)
    return redirect('/')
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>{{ title }}</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
    <div class="container">
    <div class="flex-center">
    <div class="unit-1-2 unit-1-on-mobile">
        <h1>MyDjango Auth</h1>
            {% if tips %}
        <div>{{ tips }}</div>
            {% endif %}
        <form class="form" action="" method="post">
            {% csrf_token %}
            <div>用户名:<input type="text" name='username'></div>
            <div>密 码:<input type="password" name='password'></div>
            <button type="submit" class="btn btn-primary btn-block">确定</button>
        </form>
    </div>
    </div>
    </div>
</div>
</body>
</html>

  上述代码主要实现一个简单的操作流程,流程顺序为用户注册->用户登录->访问首页,具体实现过程如下:

    1、首先用户访问用户注册界面,输入新的用户信息并单击"确定"按钮,提交用户注册信息到网站后台。

    2、后台的视图函数registerView接收表单数据,判断当前注册的用户是否存在。如果用户不存在,将表单数据保存到数据表user_myuser中,创建新的用户信息。

    3、默认情况下,新创建的用户是没有设置任何权限的,视图函数对新创建的用户设置visit_Product权限。注册成功后,程序会自动跳转到用户登录界面。

    4、在用户登录界面输入新创建的用户信息,完成用户登录后,程序会自动跳转到网站的首页。

  在user中实现了用户的权限设置,为新创建的用户添加visit_Product权限,接着在index中实现用户权限的校验。在index的路由urls.py、视图views.py和模板index.html中分别编写以下代码:

#index/urls.py
from django.urls import path
from . import views
urlpatterns = [
    # 首页的URL
    path('', views.index),
]


#index/views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required, permission_required

# 使用login_required和permission_required分别对用户登录验证和用户权限验证
@login_required(login_url='/user/login.html')
@permission_required(perm='index.visit_Product', login_url='/user/login.html')
def index(request):
    return render(request, 'index.html', locals())

  在视图函数index中使用了装饰器login_required和permission_required,分别对当前用户的登录状态和用户权限进行校验,说明如下:

    login_required:设置用户登录访问权限。如果当前用户尚未在用户登录界面完成登录而直接访问首页,程序自动跳转到登录界面,只有用户完成登录后才能访问首页。login_required的参数有redirect_field_name和login_url。

      1、参数redirect_field_name:默认值是next。当登录成功之后,程序会自动跳回之前浏览的网页。

      2、参数login_url:设置登录界面的URL地址。默认值是settings.py的属性LOGIN_URL,而属性LOGIN_URL需要开发者自行在settings.py中配置。

    permission_required:验证当前用户是否拥有相应的权限。若用户没有使用权限,程序会跳转到登录界面或者抛出异常。permission_required的参数如下。

      1、参数perm:必须参数,判断当前用户是否拥有权限。参数值为固定格式,如index.visit_Product,index为项目的App名,visit_product来自数据表auth_permission的字段codename。

      2、参数login_url:设置登录界面的URL地址,默认值为None。若不设置参数,验证失败后会抛出404异常。

      3、参数raise_exception:设置抛出异常,默认值为False。

    装饰器permission_required的作用与内置函数has_perm相同,上述代码也可以使用函数has_perm实现装饰器permission_required的功能,代码如下:

#使用函数has_perm实现装饰器permission_required功能
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required

@login_required(login_url='/user/login.html')
def index(request):
    user = request.user
    if user.has_perm('index.visit_Product'):
        
        return render(request, 'index.html', locals())
    else:
        return redirect('/user/login.html')

  最后在模板index.html中实现用户权限判断,这也是权限校验的使用方法之一。模板index.html的<header>标签代码修改如下:

<header id="top">
    <!-- 内容显示区域 :width : 1211px -->
    <div id="top_box">
        <ul class="lf">
            <li><a href="#">华为官网</a></li>
            <li><a href="#">华为荣耀</a></li>
        </ul>
        <ul class="rt">
            {#在模版中使用user变量是一个User或者AnoymousUser对象,该对象由模型MyUser实例化#}
            {% if user.is_authenticated %}
                <li>用户名: {{ user.username }}</li>
                <li><a href="{% url 'logout' %}">退出登录</a></li>
            {% endif %}
            {#在模版中使用perms变量是Permission对象,该对象由模型Permission实例化#}
            {% if perms.index.add_product %}
                <li>添加产品信息</li>
            {% endif %}
        </ul>
    </div>
</header>

   在模板index.html中分别使用变量user和perms,但从视图函数index总可以发现,视图函数并没有将变量user和perms传递给模板。其实变量user和perms是由Django自动生成的,变量的生成与配置五年级settings.py的TEMPLATES设置有关,我们查看setting.py的TEMPLATES配置信息,代码如下:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates'),
                 os.path.join(BASE_DIR, 'index/templates'),
                 os.path.join(BASE_DIR, 'user/templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

  因为TEMPLATES中定义了处理器集合context_processors,所以在解析模板Template之前,Django首先依次运行处理器集合的程序。当运行到处理器django.contrib.auth.context_processors.auth时,程序会生成变量user和perms,并且将变量传入模板变量TemplateContext中,所以在模板中可以直接使用变量user和perms。

  从上述例子可以看到,项目的user主要实现权限的设置功能;项目的index主要实现权限的使用,权限的使用主要判断当前用户是否具有权限的使用资格,而权限的判断可以从视图函数或模板语法实现。在浏览器上分别使用超级用户和普通用户登录网站,两者的首页信息如下图:

 

 

 

 

9.7  设置用户组

  顾明思义,用户组就是对用户进行分组管理,其作用是在权限控制中可以批量地对用户的权限进行分配,而不同一个一个地按用户组所分配的所有权限。例如用户组teachers拥有权限can_create_lesson,那么所有属于teachers的用户都会有can_create_lesson权限。

  我们知道用户、权限和用户组三者之间是多对多的数据关系,而用户组可以理解为用户和权限之间的中转站。设置用户组分为两个步骤:设置用户组的权限和设置用户组的用户。

  设置用户组的权限主要对数据表auth_group和auth_permission构建多对多的数据关系,数据关系保存在数据表auth_group_permissions中。以MyDjango为例,其数据库结构如下图所示:

 

数据库结构

  在数据表auth_group中创建三条数据信息:产品信息、产品类型和用户管理,每条信息在项目中代表一个用户组,如下图:

 

数据表auth_group

  我们在PyCharm的Terminal中使用Django的shell模式来实现用户组的权限配置,代码如下:

#用户组的权限配置
#导入内置模型Group和Permission
(py3_3) E:\test5\MyDjango>python manage.py shell

In [1]: from django.contrib.auth.models import Group

In [2]: from django.contrib.auth.models import Permission

#获取某个权限对象permission
In [3]: permission = Permission.objects.get(codename='visit_Product')

#获取某个用户组对象group
In [4]: group = Group.objects.get(id=1)

#将权限permission添加到用户组group中
In [5]: group.permissions.add(permission)

  上述代码将visit_Product权限添加到用户组(产品信息),功能实现过程如下:

    1、从数据表auth_group获取用户组(产品信息)对象group,对象group代表数据表总某一条数据。

    2、从数据表auth_permission获取权限(visit_Product)对象permission,对象permission代表数据表中某一条数据。

    3、使用permissions.add方法将权限对象permission与用户组对象group构建多对多数据关系并保存在数据表auth_group_permissions中。查看数据表auth_group_permissions,数据信息如下图:

  

数据表auth_group_permissions

  除了添加用户组的权限之外,还可以删除用户组已有的权限,代码如下:

#删除当前用户组group的visit_Product权限
In [6]: group.permissions.remove(permission)
#删除当前用户组group的全部权限
In [7]: group.permissions.clear()

  设置用户组的用户主要对数据表auth_group和user_myuser构建多对多数据关系,数据关系保存在数据表user_myuser_groups中。在Django的shell模式下实现用户组的用户设置,代码如下:

#将用户分配到用户组
#导入模型Group和MyUser
In [8]: from user.models import MyUser

In [9]: from django.contrib.auth.models import Group

#获取用户对象user,对象user代表用户名为user1的数据信息
In [11]: user = MyUser.objects.get(username='user1')

#获取用户组对象group,对象group代表用户组(产品信息)的数据信息
In [13]: group = Group.objects.get(id=1)

#将用户添加到用户组
In [14]: user.groups.add(group)

  上述代码将用户名为user1的用户添加到用户组(产品信息),功能实现过程与用户组的权限设置是相似的,只不过两者所使用的模型有所不同。查看数据表user_myuser_groups,数据信息如下图:

 

数据表user_myuser_groups

  除了添加用户组的用户之外,还可以删除用户组已有的用户,代码如下:

#删除用户组某一用户
In [15]: user.groups.remove(group)
#情况用户组全部用户
In [16]: user.groups.clear()

 

9.8  本章小结

  Django除了有强大的Admin管理系统之外,还提供了完善的用户管理系统。整个用户管理系统可分为三大部分:用户信息、用户权限和用户组,在数据库中分别对应数据表auth_user、auth_permission和auth_group。

  使用内置模型User和内置的函数可以快速实现用户管理功能,如用户注册、登录、密码修改、密码找回和用户注销。模型User的字段说明以及常用的内置函数如下。

模型User字段及说明

字段说明
IDint类型,数据表主键
Passwordvarchar类型,代表用户密码,在默认情况下使用pbkdf2_sha256方式来存储和管理用户的密码
last_logindatetime类型,最近一次登录的时间
is_superusertinyint类型,表示该用户是否拥有所有的权限,即是否为超级用户
Usernamevarchar类型,代表用户账号
first_namevarchar类型,代表用户的名字
last_namevarchar类型,代表用户的姓氏
Emailvarchar类型,代表用户的邮件
is_staff用来判断用户是否可以登录进入Admin系统
is_activetinyint类型,用来判断该账户的状态是否被激活
date_joineddatetime类型,账号的创建时间

 

常用的内置函数及说明

内置函数说明
authenticate验证用户是否存在,必选参数为username和password,只能用于模型User
create_user创建新的用户信息,必选参数为username,只能用于模型User
set_password修改用户密码,必选参数为password,只能用于模型User
login/logout用户的登录和注销,只能哟农户模型User
make_password密码加密处理,必选参数为password,可脱离模型User单独使用
check_password检验加密前后的密码是否相同,可脱离模型User单独使用
email_user发送邮件,只能用于模型User
send_mail发送邮件
send_mass_mail批量发送邮件
EmailMultiAlternatives发送自定义内容格式的邮件

 

   Django提供了4中模型扩展的方法:

    1、代理模型:这是一种模型继承,这种模型在数据库中无须创建新数据表。一般用于改变现有模型的行为方式,如增加新方法函数等,并且不影响现有数据库的结构。当不需要在数据库中存储额外的信息,而需要增加操作方法或更改模型的查询管理方式时,适合使用代理模型来扩展现有User模型。

    2、Profile扩展模型User:当存储的信息与模型User相关,而且并不改变模型User原有的认证方法时,可定义新的模型MyUser,并设置某个字段为OneToOneField,这样能与模型User形成一对一关联,该方法称为用户配置(User Profile)。

    3、AbstractBaseUser扩展模型User:当模型User的内置方法并不符合开发需求时,可使用该方法对模型User重新自定义设计,该方法对模型User和数据库架构影响很大。

    4、AbstractUser扩展模型User:如果模型User的内置的方法符合开发需求,在不改变这些函数方法的情况下,添加模型User的额外字段,可通过AbstractUser方式实现。使用AbstractUser定义的模型会替换原有模型User。

  用户、用户权限和用户组分别对应数据表user_myuser、auth_permission和auth_group。无论是设置用户权限、设置用户所属用户组还是设置用户组的权限,其实质都是对两个数据表之间的数据建立多对多的数据关系,说明如下:

    1、数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,实现用户权限设置。

    2、数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,实现在用户组设置用户。

    3、数据表auth_group_permissions:管理数据表auth_group和auth_permission之间的多对多关系,实现用户组设置权限。

转载于:https://www.cnblogs.com/zhaop8078/p/11603404.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值