Django自带强大的User系统,为咱们提供用户认证、权限、组等一系列功能,能够快速创建一个完整的后台功能。 但User模型并不能知足咱们的需求,例如自带的User表中没有手机号码,并且对于国人来讲表中的first_name和last_name并无什么卵用,对于实际生产中灵活的用户表来讲重写User模型是很是有必要的。html
扩展User模型
扩展User模型有许多的方法:前端
一、Proxy继承:
代理继承,此方法只可以继承User自己拥有的字段,并不可以添加和删改,不会影响表中原有的结构,可是能够定义一些方法来获取咱们须要的数据:python
from django.contrib.auth.models import User class ProxyUser(User): class Meta: proxy = True # 定义代理模型 def get_data(self): return self.objects.filter("过滤条件")
二、一对一外键:
若是咱们对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()
三、继承AbstractUser自定义模型:
Django自带的User模型就是继承的AbstractUser类,所以咱们能够经过继承AbractUser类自定义User模型:django
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 user def create_user(self,username,password,email,**kwargs): # 建立普通用户 kwargs['is_superuser'] = False return self._create_user(username,password,email,**kwargs) def create_superuser(self,username,password,email,**kwargs): # 建立超级用户 kwargs['is_superuser'] = True kwargs['is_staff'] = True return self._create_user(username,password,email,**kwargs) class User(AbstractUser): # 自定义User GENDER_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=True REQUIRED_FIELDS = ['email'] # 建立用户时必须填写的字段,除了该列表里的字段还包括password字段以及USERNAME_FIELD中的字段 EMAIL_FIELD = 'email' # 发送邮件时使用的字段 objects = UserManager() def get_full_name(self): return self.username def get_short_name(self): return self.username class 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模型了。安全
四、继承AbstractBaseUser类、PermissionsMixin类自定义User模型:
继承AbstracUser类自定义User有一个很差的地方,就是咱们没有办法改变其已有的字段,好比first_name和last_name咱们并不须要,这个时候就能够继承AbstractBaseUser和PermissionsMixin类彻底重写User模型:session
from django.contrib.auth.models import AbstractBaseUser,PermissionsMixin,BaseUserManager from shortuuidfield import ShortUUIDField from django.db import models class 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 user def create_user(self,username,password,email,**kwargs): kwargs['is_superuser'] = False return self._create_user(username,password,email,**kwargs) def create_superuser(self,username,password,email,**kwargs): kwargs['is_superuser'] = True kwargs['is_staff'] = True return self._create_user(username,password,email,**kwargs) class User(AbstractBaseUser,PermissionsMixin): # 继承AbstractBaseUser,PermissionsMixin GENDER_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.username def get_short_name(self): return self.username class Meta: verbose_name = "用户" verbose_name_plural = verbose_name
此时数据库中只会生成咱们定义好的字段。 定义好了User模型咱们就可使用Django自带的登陆验证和权限系统了。 首先注册功能: form.pyapp
from django.forms import Form from django.forms import fields from django.core.exceptions import ValidationError class 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 JsonResponse User = 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 fields class 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自带退出功能,会帮助咱们删除相关session return 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模型和权限之间能够经过如下几种方式来进行管理: 一、user.user_permissions.set(permission_list):直接给定一个权限的列表。 二、user.user_permissions.add(permission,permission,...):一个个添加权限。 三、user.user_permissions.remover(permission,permission):一个个删除权限。 四、user.user_permissions.clear():清除权限 五、user.has_perm('<app_name>.<codename>'):判断是否拥有某个权限,权限参数是一个字符串,格式是app_name.codename。 六、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数据表。 分组操做: 一、Group.objects.create(group_name):建立分组 二、group.permission:某个分组上的权限。多堆多的关系。
group.permission.add:添加权限。 group.permission.remove:移除权限。 group.permission.clear:清除全部权限。 user.get_group_permission():获取用户所属组的权限。 三、user.groups:某个用户上的全部分组。多对多的关系。 在模板中使用权限: 在settings.TEMPLATES.OPTIONS.context_processors下,由于添加了django.contrib.auth.context_processors.auth上下文处理器,所以能够在模板中直接经过 perms来获取用户的全部权限:
{% if perms.View.view_cart %} 购物车详情 {% endif %}
原文连接:https://blog.csdn.net/weixin_44951273/article/details/101028522