Django之auth模块

auth模块是Django内置的用户权限管理模块:比如用户的创建,认证,登入,注销等。当我们创建一个APP时,auth模块就会自动添加在 INSTALLED_APPS=['django.contrib.auth',]

auth常用的几个方法:

  User模型(auth/models.py中):用来维护用户信息的模型;比如用户的创建,认证等; 源码中User模型继承自AbstractUser,而AbstractUser继承自AbstractBaseUser,有以下字段:

    username: 最长150个字符,必须传递

    first_name:外国人的第一个名字

    last_name: 外国人的最后一个名字

    email: 邮箱

    is_staff: 是否为员工,可以进入后台管理系统

    is_active: 是否是可用的。对于一些想要删除账号的数据,我们设置这个值为False就可以了,而不是真正的从数据库中删除。

    date_joined: 账号创建的时间。

    objects = UserManager():  定义objes方法(两个方法一个是创建普通用户:create_user()和创建一个超级用户create_superuser())

    EMAIL_FIELD = "email"

    USERNAME_FIELD = "username"  唯一验证身份的标志

    REQUIRED_FIELDS = ["email"]

    而AbstractBaseUser中的字段有:(它中的字段和方法对于User和AbstractUser都可以用)

    password :密码,经过哈希处理的

    last_login:最后登入时间

    is_active = True :默认账号是可用状态

    常用的几个方法:

    get_username() :返回用户名

    save():保存

    set_password():设置密码

    check_password():检验密码是否正确

    User模型的基本使用方法:

      使用User模型之前我们需要先把模型映射的数据库中即(makemigrations,migrate),数据库中的auth_user表就是保存用户信息的。

      上代码: 

from django.shortcuts import render,HttpResponse
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
def index(request):
    User.objects.create_user("李四","zhangsan@163.com","123456")   #创建一个普通用户,参数可以只传递一个用户名,其他的可传可不传
    User.objects.create_superuser("里斯","lisi@163.com","111111")   #创建一个超级用户,三个参数用户名,邮箱,密码必须传递
    user = User.objects.first()  
    user.set_password("qweqwe")  #修改密码,修改之后必须保存
    user.save()
    user = authenticate(request,username = "李四",password = "123456")  #验证这个用户存不存在,如果存在返回这个用户的用户名
    if user:
        print("有这个用户")
    else:
        print("没有这个用户")
    return HttpResponse("ok")

    User模型虽然已经很强大了,但是有时依然不能满足我们的需求,比如我们想再定义几个字段,或者添加一些方法什么的,这个时候我们就需要扩展User模型,方法有以下四种:

    User模型的扩展一之proxy模型:

      使用范围:我们对它的字段很满意了没有其他可以添加,只是需要再添加一些方法,比如想获取所有的超级管理员;

      注意:这种方式只能添加方法,不能添加字段,除了添加的这个方法之外和User没有区别

      app/models.py中的代码:

 

from django.contrib.auth.models import User

class getsuperuser(User):  #定义一个类继承自User类
    class Meta:
        proxy = True   #设置代理模式
    @classmethod
    def get_superuser(cls):   #定义一个类方法(获取所有的管理员)
        return cls.objects.filter(is_superuser=True)

 

      app/views.py中的代码:

from django.shortcuts import render,HttpResponse
from django.contrib.auth.models import User
from .models import getsuperuser  #导入这个模块

userlist = getsuperuser.get_superuser()   #获取所有的管理
    for user in userlist:
        print(user)

userlist01 = User.objects.all()
    print(userlist01)
userlist02 = getsuperuser.objects.all()    #在这种代理模式中User模型和代理模型的使用是一样的即Uer.objects.all()等价于getsuperuser.objects.all()
    print(userlist02)
return HttpResponse("ok")

    User模型的扩展二之一对一外键:(这种方式是创建一个新的表,用来保存一些新的字段并且和User表一一对应)

      使用范围:如果我们要添加一个字段和方法

      app/models.py中的代码:

 

from django.db import models
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save

class UserExtension(models.Model):    #定义一个User一对一的外键类
    user = models.OneToOneField(User,on_delete=models.CASCADE,related_name="extension")  #外键User
    telephone = models.CharField(max_length=11,unique=True)
    school = models.CharField(max_length=100)
@receiver(post_save,sender = User)    #定义一个信号机制,信号的发送者sender是User,信号是post_save,当User这个实例被创建的时候同时创建一个user的外键,否则保存这个实例和外键
def handle_user_extenson(sender,instance,created,**kwargs):
    if created:         //如果User被创建了,那么同时创建一个UserExtension,并且外键与User对应
        UserExtension.objects.create(user=instance)
    else:
        instance.extension.save()    //如果User被保存,则UserExtension也保存

 

    app/views.py中代码:

 user = User.objects.create_user("王二","wanger@163.com","123123")  #创建一个用户
    user.extension.telephone = "18899998888"  #给这个用户添加手机号
    user.extension.school = "北京交通大学"     #给这里用户添加一个学校
    user.save()

    User模型的扩展三之继承自AbstractUser:

      使用范围:如果我们不想改变原来User的内容,又想在数据库中的同一个表中添加一些新的字段

      User本身也是继承这个AbstractUser模型写的,相当于我们在原User的基础上重新写了User

      因为objects这个方法也在这个User模型中,所以我们可以重新定义objects;

      注意:(1)这种方式破坏了User数据表的结构,所以必须在第一次migrate之前定义好(2)在setting中设置:AUTH_USER_MODEL = 'front.User'(这里的front是你的app)

      app/models.py中的代码

 

rom django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import AbstractUser,AbstractBaseUser,BaseUserManager


class UserManager(BaseUserManager):  #重新定义一个UserManager
    def _create_user(self,telephone,username,password,**kwargs):
        if not telephone:
            raise ValueError("必须要有手机号")
        if not password:
            raise ValueError("必须要有密码")
        user = self.model(telephone=telephone,username=username,**kwargs)
        user.set_password(password)
        user.save()
        return user

    def create_user(self,telephone,username,password,**kwargs):
        kwargs["is_superuser"] = False
        return self._create_user(telephone=telephone,username=username,password=password,**kwargs)

    def create_superuser(self,telephone,username,password,**kwargs):
        kwargs["is_superuser"] = True
        return self._create_user(telephone=telephone,username=username,password=password,**kwargs)

class User(AbstractUser):
    telephone = models.CharField(max_length=11,unique=True)
    school = models.CharField(max_length=100)

#指定telephone作为USERNAME_FIELD,以后使用authenticate;函数验证的时候,就可以根据telephone来验证;而不是原来的username
    USERNAME_FIELD = 'telephone'
    REQUIRED_FIELDS = []
  objects = UserManager() # 重新定义Manager对象,在创建user的时候使用telephone,username和password,而不是使用username和password

 

    app中views.py中的代码

from django.shortcuts import render,HttpResponse
from django.contrib.auth import authenticate
from .models import User  #这里需要导入的是models下面的User(注意)
def index(request):
    telephone = '18899996666'
    password = '111111'
    username = '张三'
    User.objects.create_superuser(telephone=telephone,username=username,password=password)
    user = authenticate(request,username = "18899996666",password = "111111")  #这里的username并不是真正的username而是代表USERNAME_FIELD的值,使用手机号验证,返回的是一个手机号
    print(user)    //返回的是一个手机号
   print(user.username) //返回的是一个用户名
return HttpResponse("ok")

    User模型的扩展四之继承自AbstractBaseUser:(这时其实就相当于在写一个AbstractUser)

    使用范围:如果既想改变验证方式,又想添加字段,还不想要User原来的字段,可以完全重新写一个User;继承自AbstractBaseUser

    注意(和上面一样):(1)这种方式破坏了User数据表的结构,所以必须在第一次migrate之前定义好(2)在setting中设置:AUTH_USER_MODEL = 'front.User'(这里的front是你的app)

    app/models.py中的代码

 

from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import AbstractUser,AbstractBaseUser,BaseUserManager,PermissionsMixin


class UserManager(BaseUserManager):  #和上面一样重新定义了bjects
    def _create_user(self,telephone,username,password,**kwargs):
        if not telephone:
            raise ValueError("必须要有手机号")
        if not password:
            raise ValueError("必须要有密码")
        user = self.model(telephone=telephone,username=username,**kwargs)
        user.set_password(password)
        user.save()
        return user

    def create_user(self,telephone,username,password,**kwargs):
        kwargs["is_superuser"] = False
        return self._create_user(telephone=telephone,username=username,password=password,**kwargs)

    def create_superuser(self,telephone,username,password,**kwargs):
        kwargs["is_superuser"] = True
        return self._create_user(telephone=telephone,username=username,password=password,**kwargs)


class User(AbstractBaseUser,PermissionsMixin):  #定义User继承在AbstractBaseUser,PermissionsMixin(其实这时相当于在写一个AbstractUser)
    telephone = models.CharField(max_length=11,unique=True)
    username = models.CharField(max_length=10,unique=True)


    USERNAME_FIELD = "telephone"
    REQUIRED_FIELDS = []

    objects = UserManager()

    def get_full_name(self):
        return self.username

    def get_short_name(self):
        return self.username

     app/views.py中的代码:

from django.shortcuts import render,HttpResponse
from django.contrib.auth import authenticate
from .models import User
def index(request):
    telephone = '18899996666'
    password = '111111'
    username = '张三'
    User.objects.create_superuser(telephone=telephone,username=username,password=password)
    user = authenticate(request,telephone = "18899996666",password = "111111")
    print(user)
    return HttpResponse("ok")

  login/logout模块和登入限制:

from django.shortcuts import render,HttpResponse,redirect,reverse
from django.contrib.auth import authenticate,login,logout
from .models import User
from .forms import LoginForm
from django.contrib.auth.decorators import login_required


def my_login(request):    //登入
    if request.method == "GET":   //如果是get请求则返回登入页面
        return render(request,"login.html")
    if request.method == "POST":    //如果是post请求,则交给表单验证
        form = LoginForm(request.POST)
        if form.is_valid():
            telephone = form.cleaned_data.get("telephone")
            password = form.cleaned_data.get("password")
            remember = form.cleaned_data.get("remember")
            user = authenticate(request,telephone=telephone,password=password)  //验证
            if user and user.is_active:
                login(request,user)  //登入
                if remember:    //设置session
                    request.session.set_expiry(None)
                else:
                    request.session.set_expiry(0)
                next_url = request.GET.get("next")  //如果有next,则直接跳转到这个页面(限制登入时django自动添加了next参数)
                if next_url:
                    return redirect(next_url)
                else:
                    return HttpResponse("登入成功")
            else:
                return HttpResponse("用户名或者密码错误")
        else:
            print(form.errors.get_json_data())
            return redirect(reverse("login"))

def my_logout(request):
    logout(request)  //退出登入
    return HttpResponse("退出成功")

@login_required(login_url="/login/")  //限制登入装饰器,login_url表示失败后去哪个页面
def my_file(request):
    return HttpResponse("个人中心")

form.py

from django import forms
from django.contrib.auth import get_user_model  //获取User模型(这个方法是或者setting中的AUTH_USER_MODEL = "login.User"class LoginForm(forms.ModelForm):
    remember = forms.BooleanField(required=False)
    telephone = forms.CharField(max_length=11)
    class Meta:
        model = get_user_model()
        fields = ["password"]  //这里不能添加telephone,因为Model.Form会把这个手机号去数据库中验证,如果有直接报错,所以telephone自己定义一个
        error_messages={
            "telephone":{
                "required":"手机号必须有"
            },
            "password":{
                "required": "手机号必须有"
            }
        }

  权限

    添加权限两种方式第一种是模型中添加权限:

class Article(models.Model):
    author = models.ForeignKey(get_user_model(),on_delete=models.CASCADE)
    title = models.CharField(max_length=20)
    content = models.CharField(max_length=100)

    class Meta:
        permissions = [
            ("black_article","拉黑文章")
        ]

  第二种方式代码中添加权限:

def add_permissions(request):
    content_type = ContentType.objects.get_for_model(Article)
    Permission.objects.create(name="可编辑的权限",codename="edit_article",content_type=content_type)
    return HttpResponse("添加成功")

   User模型和模型权限之间的管理

def operate_permissions(request):
    user = User.objects.first()
    content_type = ContentType.objects.get_for_model(Article)   //
    print(content_type.id)
    permissions = Permission.objects.filter(content_type=content_type)   //获取这个模型所有的权限
    for permission in permissions:
        print(permission)
    # user.user_permissions.set(permissions)  #一次性添加多个权限
    # user.user_permissions.clear()   #一次性清楚所有权限
    user.user_permissions.add(permissions[0],permissions[1])  //一次添加一个权限
    user.user_permissions.add(*permissions)
    user.user_permissions.remove(permissions[1])   //一次移除一个权限
    if user.has_perm("login.aa_article"):   //检查一次是否拥有某个权限,格式是app_name.codename
        print("有这个权限")
    permissions_all = user.get_all_permissions()   //获取user所有的权限
    print(permissions_all)
    return HttpResponse("添加成功")

   权限装饰器(规定必须拥有什么样的权限才能访问视图函数)

from django.contrib.auth.decorators import permission_required  //导入装饰器,这个装饰器做了两件事(一件事验证是否登入,另一件事验证是否有权限)

@permission_required("login.add_article",login_url="/login/",raise_exception=True)  //规定只有add_article的权限才能访问这个视图函数也可以是一个列表["login.add_article","login.view_article"];login_url表示没有权限的时候跳转的页面,raise_exception=True表示没有权限的时候跳转到403页面
def add_article(request):
   
    return HttpResponse("添加文章的页面")

   权限分组:

def operate_group(request):
    # group = Group.objects.create(name="财务")  #添加一个分组
    # content_type = ContentType.objects.get_for_model(Article)
    # permissions = Permission.objects.filter(content_type=content_type)  //获得这个模型的所有权限
    group = Group.objects.filter(name="财务").first()  //获得第一个分组
    # group.permissions.set(permissions)   //给这个分组添加权限
    # group.save()  //保存
    user = User.objects.first()
    # user.groups.add(group)  //把这个user添加到这个组
    # user.save()
    # permissions = user.get_group_permissions()  //获得所在组的所有权限
    # print(permissions)
    if user.has_perm("login.add_article"):
        print("有这个权限")
    #has_perm(),先去判断user里面有没有这个权限,如果没有再去所在分组中查找
    return HttpResponse("分组")

  模板中使用权限:有一些页面只想展示给有权限的人看,比如有关财务的页面只给具有财务权限的人看。

  #因为setting.TEMPLATS.OPTIONS.context_processors下添加了django.contrib.auth.context_processors.auth上下文处理器,所以在模板中可以直接通过perms来获取用户的所有权限
{% if perms.login.add_article %} <p>添加文章</p> {% endif %}

 

 

 

 

 

posted @ 2018-12-20 01:06  漏斗倒过来  阅读(309)  评论(0编辑  收藏  举报