Django自定义User模型以及用户系统(用户、权限、组)的使用
Django自带强大的User系统,为我们提供用户认证、权限、组等一系列功能,可以快速建立一个完整的后台功能。
但User模型并不能满足我们的需求,例如自带的User表中没有手机号码,而且对于国人来说表中的first_name和last_name并没有什么卵用,对于实际生产中灵活的用户表来说重写User模型是非常有必要的。
扩展User模型
扩展User模型有许多的方法:
1、Proxy继承:
代理继承,此方法只能够继承User本身拥有的字段,并不能够添加和删改,不会影响表中原有的结构,但是可以定义一些方法来获取我们需要的数据:
from django.contrib.auth.models import User
class ProxyUser(User):class Meta:proxy = True # 定义代理模型def get_data(self):return self.objects.filter("过滤条件")
2、一对一外键:
如果我们对User本身的字段和验证方法没有要求,只是想要增加额外字段,可以通过创建另外一张表去关联User表,从而添加额外字段,并且我们可以写一个接受保存模型的信号处理方法,只要User调用了save方法,那么关联表就会自动添加一条数据与User新添加的用户进行绑定:
from django.db import models
from django.contrib.auth.models import User
from django.dispatch import receiver # 导入receiver监听信号
from django.db.models.signals import post_save # 导入post_save信号
class ExtensionUser(object):"""创建一对一模型,并添加新的字段"""user = models.OneToOneField(User,on_delete=models.CASCADE)telephone = models.CharField(max_length=11,verbose_name="手机号码")@receiver(post_save,sender=User) # 监听到post_save事件且发送者是User则执行create_extension_user函数
def create_extension_user(sender,instance,created,**kwargs):"""sender:发送者instance:save对象created:是否是创建数据"""if created: # 如果创建对象,ExtensionUser进行绑定ExtensionUser.objects.create(user=instance)else:# 如果不是创建对象,同样将改变进行保存instance.extension.save()
3、继承AbstractUser自定义模型:
Django自带的User模型就是继承的AbstractUser类,因此我们可以通过继承AbractUser类自定义User模型:
from django.contrib.auth.models import BaseUserManager,AbstractUser
from shortuuidfield import ShortUUIDField # 使用shortuuid作为User表的主键,使数据更加的安全class UserManager(BaseUserManager): #自定义Manager管理器def _create_user(self,username,password,email,**kwargs):if not username:raise ValueError("请传入用户名!")if not password:raise ValueError("请传入密码!")if not email:raise ValueError("请传入邮箱地址!")user = self.model(username=username,email=email,**kwargs)user.set_password(password)user.save()return userdef create_user(self,username,password,email,**kwargs): # 创建普通用户kwargs['is_superuser'] = Falsereturn self._create_user(username,password,email,**kwargs)def create_superuser(self,username,password,email,**kwargs): # 创建超级用户kwargs['is_superuser'] = Truekwargs['is_staff'] = Truereturn self._create_user(username,password,email,**kwargs)class User(AbstractUser): # 自定义UserGENDER_TYPE = (("1","男"),("2","女"))uid = ShortUUIDField(primary_key=True)username = models.CharField(max_length=15,verbose_name="用户名",unique=True)nickname = models.CharField(max_length=13,verbose_name="昵称",null=True,blank=True)age = models.IntegerField(verbose_name="年龄",null=True,blank=True)gender = models.CharField(max_length=2,choices=GENDER_TYPE,verbose_name="性别",null=True,blank=True)phone = models.CharField(max_length=11,null=True,blank=True,verbose_name="手机号码")email = models.EmailField(verbose_name="邮箱")picture = models.ImageField(upload_to="Store/user_picture",verbose_name="用户头像",null=True,blank=True)home_address = models.CharField(max_length=100,null=True,blank=True,verbose_name="地址")card_id = models.CharField(max_length=30,verbose_name="身份证",null=True,blank=True)is_active = models.BooleanField(default=True,verbose_name="激活状态")is_staff = models.BooleanField(default=True,verbose_name="是否是员工")date_joined = models.DateTimeField(auto_now_add=True)USERNAME_FIELD = 'username' # 使用authenticate验证时使用的验证字段,可以换成其他字段,但验证字段必须是唯一的,即设置了unique=TrueREQUIRED_FIELDS = ['email'] # 创建用户时必须填写的字段,除了该列表里的字段还包括password字段以及USERNAME_FIELD中的字段EMAIL_FIELD = 'email' # 发送邮件时使用的字段objects = UserManager()def get_full_name(self):return self.usernamedef get_short_name(self):return self.usernameclass Meta:verbose_name = "用户"verbose_name_plural = verbose_name
自定义好User模型之后还需要在settings中设置系统才会识别当前User模型作为系统默认User模型,settings中需要先安装app,然后添加AUTH_USER_MODEL=‘app.User’:
之后重新python manage.py makemigrations
,python manage.py migrate
就可以使用该模型作为系统User模型了。
4、继承AbstractBaseUser类、PermissionsMixin类自定义User模型:
继承AbstracUser类自定义User有一个不好的地方,就是我们没有办法改变其已有的字段,比如first_name和last_name我们并不需要,这个时候就可以继承AbstractBaseUser
和PermissionsMixin
类完全重写User模型:
from django.contrib.auth.models import AbstractBaseUser,PermissionsMixin,BaseUserManager
from shortuuidfield import ShortUUIDField
from django.db import modelsclass UserManager(BaseUserManager):def _create_user(self,username,password,email,**kwargs):if not username:raise ValueError("请传入用户名!")if not password:raise ValueError("请传入密码!")if not email:raise ValueError("请传入邮箱地址!")user = self.model(username=username,email=email,**kwargs)user.set_password(password)user.save()return userdef create_user(self,username,password,email,**kwargs):kwargs['is_superuser'] = Falsereturn self._create_user(username,password,email,**kwargs)def create_superuser(self,username,password,email,**kwargs):kwargs['is_superuser'] = Truekwargs['is_staff'] = Truereturn self._create_user(username,password,email,**kwargs)class User(AbstractBaseUser,PermissionsMixin): # 继承AbstractBaseUser,PermissionsMixinGENDER_TYPE = (("1","男"),("2","女"))uid = ShortUUIDField(primary_key=True)username = models.CharField(max_length=15,verbose_name="用户名",unique=True)nickname = models.CharField(max_length=13,verbose_name="昵称",null=True,blank=True)age = models.IntegerField(verbose_name="年龄",null=True,blank=True)gender = models.CharField(max_length=2,choices=GENDER_TYPE,verbose_name="性别",null=True,blank=True)phone = models.CharField(max_length=11,null=True,blank=True,verbose_name="手机号码")email = models.EmailField(verbose_name="邮箱")picture = models.ImageField(upload_to="Store/user_picture",verbose_name="用户头像",null=True,blank=True)home_address = models.CharField(max_length=100,null=True,blank=True,verbose_name="地址")card_id = models.CharField(max_length=30,verbose_name="身份证",null=True,blank=True)is_active = models.BooleanField(default=True,verbose_name="激活状态")is_staff = models.BooleanField(default=True,verbose_name="是否是员工")date_joined = models.DateTimeField(auto_now_add=True)USERNAME_FIELD = 'username'REQUIRED_FIELDS = ['email']EMAIL_FIELD = 'email'objects = UserManager()def get_full_name(self):return self.usernamedef get_short_name(self):return self.usernameclass Meta:verbose_name = "用户"verbose_name_plural = verbose_name
此时数据库中只会生成我们定义好的字段。
定义好了User模型我们就可以使用Django自带的登录验证和权限系统了。
首先注册功能:
form.py
from django.forms import Form
from django.forms import fields
from django.core.exceptions import ValidationErrorclass RegisterForm(Form):username = fields.CharField(required=True,min_length=3,max_length=18,error_messages={"required":"用户名不可以为空!","min_length":"用户名不能低于3位!","max_length":"用户名不能超过18位!"})password1 = fields.CharField(required=True,min_length=3,max_length=18,error_messages={"required":"密码不可以空","min_length": "密码不能低于3位!","max_length": "密码不能超过18位!"})password2 = fields.CharField(required=False)email = fields.EmailField(required=True,error_messages={"required":"邮箱不可以为空!"},)def clean_password2(self):if not self.errors.get("password1"):if self.cleaned_data["password2"] != self.cleaned_data["password1"]:raise ValidationError("您输入的密码不一致,请重新输入!")return self.cleaned_data
views.py
from django.shortcuts import render
from django.contrib.auth import get_user_model
from .forms import *
from django.http import JsonResponseUser = get_user_model() # 获取User模型def register(request):if request.method == "GET":return render(request,"register.html")else:form = RegisterForm(request.POST)if form.is_valid():username = form.cleaned_data["username"]password = form.cleaned_data["password1"]email = form.cleaned_data["email"]username_exists = User.objects.filter(username=username).exists()if username_exists:return JsonResponse({"code":400,"message":"验证失败","data":{"username":"您输入的用户名已存在!","password1":"","password2":"","email":""}})email_exists = User.objects.filter(email=email).exists()if email_exists:return JsonResponse({"code": 400, "message":"验证失败","data":{"username": "","password1":"","password2":"", "email": "您输入的邮箱已存在!"}})User.objects.create_user(username=username,password=password,email=email)return JsonResponse({"code": 200,"message":"验证通过", "data":{"username": "","password1":"","password2":"", "email": ""}})else:return JsonResponse({"code":400,"message":"验证失败","data":{"username":form.errors.get("username"),"password1":form.errors.get("password1"),"password2":form.errors.get("password2"),"email":form.errors.get("email")}})
登录功能
form.py:
from django.forms import Form
from django.forms import fieldsclass LoginForm(Form):username = fields.CharField(required=True,min_length=3,max_length=18,error_messages={"required":"用户名不可以为空!","min_length":"用户名不能低于3位!","max_length":"用户名不能超过18位!"})password = fields.CharField(required=True,error_messages={"required":"密码不可以空",})
views.py:
from django.shortcuts import render
from .forms import *
from django.http import JsonResponse
from django.contrib.auth import authenticate
from django.contrib.auth import login
# 登录视图名称不能起成login,与自带login函数重名
def loginView(request):if request.method == "GET":return render(request,"login.html")else:form = LoginForm(request.POST)if form.is_valid():username = form.cleaned_data.get("username")password = form.cleaned_data.get("password")remember = int(request.POST.get("remember"))user = authenticate(request,username=username,password=password) # 使用authenticate进行登录验证,验证成功会返回一个user对象,失败则返回None# 使用authenticate验证时如果is_active为False也会返回None,导致无法判断激活状态,# 此时可以在seetings中配置:# AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']if user and user.is_active: # 如果验证成功且用户已激活执行下面代码login(request,user) # 使用自带的login函数进行登录,会自动添加session信息request.session["username"] = username # 自定义session,login函数添加的session不满足时可以增加自定义的session信息。if remember:request.session.set_expiry(None) # 设置session过期时间,None表示使用系统默认的过期时间 else:request.session.set_expiry(0) # 0代表关闭浏览器session失效return JsonResponse({"code": 200,"message":"验证通过","data":{ "error":""}})elif user and not user.is_active:return JsonResponse({"code": 400, "message": "用户未激活", "data": {"error": "该用户还没有激活,请<a href='#'>激活</a>"}})else:return JsonResponse({"code": 400, "message": "验证失败", "data": {"error": "用户名或密码错误"}})else:return JsonResponse({"code":400,"message":"用户名或密码格式错误","data":{"error":"用户名或密码错误"}})
退出功能
from django.contrib.auth import logout
from django.shortcuts import redirect
# 视图名不能起成logout
def logoutView(request):logout(request) # 调用django自带退出功能,会帮助我们删除相关sessionreturn redirect(request.META["HTTP_REFERER"])
此时我们就完成了通过自定义User模型实现注册登录以及退出一系列的功能,配合前端页面就可以完美实现了。
用户与权限管理
定义了用户模型,就不可避免的涉及到了用户权限问题,Django同样内置了Permission系统,该权限系统都是针对表或者模型级别的,比如某个模型上的数据可以进行增删改查,他不能够针对数据级别,比如某个表中的某条数据是否能够进行增删改查操作(如果要实现数据级别的,可以考虑使用django-guardian)。创建完一个模型后,针对该模型默认有增、删、改、查四种权限,权限存储了数据库中的auth_permission表中:
codename表示权限的名字,name表示权限的作用,content_type_id表示某张表的id,即用来绑定数据表的,他关联django_content_type这张表:
添加权限的两种方法:
#通过定义模型来添加权限:
class Address(models.Model):"""收货地址"""recv_address = models.TextField(verbose_name = "收货地址")receiver = models.CharField(max_length=32,verbose_name="接收人")recv_phone = models.CharField(max_length=32,verbose_name="收件人电话")post_number = models.CharField(max_length=32,verbose_name="邮编")buyer_id = models.ForeignKey(to=User,on_delete = models.CASCADE,verbose_name = "用户id")class Meta:permissions = (("view_addresses", "查看地址"),)
# 通过代码添加权限
from django.contrib.auth.models import Permission,ContentType
from .models import Address
content_type = ContentType.objects.get_for_model(Address)
permission = Permission.objects.create(name = "查看地址",codename = "view_addresses",content_type = content_type)
User模型和权限之间可以通过以下几种方式来进行管理:
1、user.user_permissions.set(permission_list)
:直接给定一个权限的列表。
2、user.user_permissions.add(permission,permission,...)
:一个个添加权限。
3、user.user_permissions.remover(permission,permission)
:一个个删除权限。
4、user.user_permissions.clear()
:清除权限
5、user.has_perm('<app_name>.<codename>')
:判断是否拥有某个权限,权限参数是一个字符串,格式是app_name.codename。
6、user.get_all_permission()
:获得所有权限。
我们可以通过appname_user_user_permission这张表来查看某个用户是否拥有某项权限:
权限限定装饰器:
使用django.contrib.auth.decorators.permission_required可以很方便的检查某个用户是否拥有某项权限:
from django.contrib.auth.decorators import permission_required
@permission_required('Cart.view_cart',login_url="/login/",raise_exception=True)
# 第一个参数代表权限,login_url表示没有登录的话需要跳转的页面,raise_exception表示没有权限是返回403错误,默认是False,会跳转到login_url指定的页面。
def view_cart(request):reture HttpResponse("您可以查看购物车")
分组
权限有很多,一个模型就最少有四个权限,如果一些用户拥有相同的权限,每次都需要重复添加是很不方便的,此时分组功能就可以帮我们解决这个问题,我们可以把一些权限归类,然后添加到某个分组中,之后再把和需要赋予这些权限的用户添加的这个分组中,就比较方便的进行管理了。分组我们使用的是django.contrib.auth.models.Group模型,每个用户组拥有id和name两个字段该模型在数据库被映射为auth_group数据表。
分组操作:
1、Group.objects.create(group_name)
:创建分组
2、group.permission
:某个分组上的权限。多堆多的关系。
group.permission.add
:添加权限。group.permission.remove
:移除权限。group.permission.clear
:清除所有权限。user.get_group_permission()
:获取用户所属组的权限。
3、user.groups
:某个用户上的所有分组。多对多的关系。
在模板中使用权限:
在settings.TEMPLATES.OPTIONS.context_processors
下,因为添加了django.contrib.auth.context_processors.auth
上下文处理器,因此可以在模板中直接通过 perms
来获取用户的所有权限:
{% if perms.View.view_cart %}购物车详情
{% endif %}
Django自定义User模型以及用户系统(用户、权限、组)的使用相关推荐
- 【linux系统用户管理】
用户和组存在的意义 1.系统上的每个进程都需要特定的用户运行 2.每个文件都有特定的用户拥有 3.访问文件或目录收到用户的限制 4.进程能够以何种方式访问某一个文件或目录,与进程所关联的用户有关 id ...
- linux运维管理系统培训,Linux运维教程之Linux系统用户与组管理
今天小编要跟大家分享的文章是关于Linux运维教程之Linux系统用户与组管理.正在从事Linux运维工作和学习的小伙伴们来和小编一起看一看吧,希望本篇文章能够对大家有所帮助. 一.Linux系统用户 ...
- 05 Linux系统用户与组管理
Linux系统用户与组管理 用户信息管理 用户增删改查 用户权限管理 用户组管理 nginx / tomcat 用户登录 [root@myserver ~] # 用户名称@主机名称 位置 (可以使用 ...
- oracle中角色的用户和权限管理,用户角色与权限控制
一.oracle中的用户 系统用户:sys.system(系统创建的用户) 登录命令:sqlplus sys/密码 as sysdba 备注:sys是oracle数据库中最高权限用户,角色为sysdb ...
- CRM系统操作权限的实现
CRM系统操作权限的实现 操作权限功能: (一)粗粒度权限控制:(即防止用户没有登录手动输入地址) (二)细粒度权限控制:(即防止没有权限的操作) 1.菜单的操作的权限 2.功能的操作权限 PO实体的 ...
- django进阶07用户模块与权限系统
原创:django进阶07用户模块与权限系统 Django默认提供了用户权限管理模块auth, 1 2 3 user表,User是auth模块中维护用户信息的表,在数据库中该表被命名为auth_use ...
- vs code写ipynb怎么添加目录_用Django写招聘网站2——用户系统
书接上文,今天来通过allauth开发下招聘网站的用户系统, allauth是什么?它可以理解为前文提到的五个模块中的accounts模块,是一个通用用户注册管理的通用模块.大师给咱们写好了,直接拿来 ...
- django(权限、认证)系统——用户Login,Logout
django(权限.认证)系统--用户Login,Logout 上面两篇文章,讲述的Django的Authentication系统的核心模型对象User API和相关的使用,本文继续深入,讨论如何在W ...
- 若依系统用户权限模型分析
本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:若依系统用户权限模型分析 用户-角色-菜单 1.基本使用 这是一个经典的用户-角色-权限的模型,其中菜单就代表了权限(因为权限就代表能否访问某个 ...
最新文章
- NanoPi NEO Air使用四:操作GPIO
- 使用 jQuery 简化 Ajax 开发.
- Android设备音频部分一些概念
- 关于matlab中princomp的使用说明讲解
- 王力宏《十八般武艺》新碟 测评
- java复习题_java习题-(static)
- [导入]完成可脚本调用的视频录制控件
- Pro ASP.NET MVC - [3]Prerequisites(前提) - [2]Domain Modeling
- react实现动画电子倒计时组件
- 2021年中国人工智能市场发展现状
- 现代公司制度的法理学基础 (贾登勋 王勇)
- OneNET麒麟座应用开发之十:空气质量数据监测站项目总结
- openshift Tekton pipeline 实践
- 点云配准算法ICP及其各种变体
- 流行学习,比较好的一篇博客
- 迅为4412开发板-实验LEDS驱动一
- 不晓得这是航拍器还是探测器之类的,肉眼根本无法看清
- 如何读关于设计模式的那几本书
- USB协议学习笔记 - 虚拟串口Virtual Port Com用于LOG打印
- 2018洛谷8月月赛第一题_U28036 Nagisa loves Tomoya
热门文章
- 什么是大小端?如何判断大小端
- C++ 数组array与vector的比较
- C++之Queue容器初学
- 解决C#界面假死问题
- PIE-engine 教程 ——使用阈值法加载指定区域的大蒜种植区域并统计其面积
- 安庆师范大学计算机学院书记,安庆师范大学计算机与信息学院导师教师师资介绍简介-陈春生...
- 乐园管理系统| 乐园小程序 | 数字化门店会员管理
- 东莞市重点培育上市后备科技企业名单(科技局)
- 2022-2028年全球与中国皮卡后视镜行业市场前瞻与投资战略规划分析
- 网络安全ctf比赛/学习资源整理,解题工具、比赛时间、解题思路、实战靶场、学习路线,推荐收藏!...