# 允许自定义用户模型类
AUTH_USER_MODEL = 'users.User'
# 修改默认的认证后端
AUTHENTICATION_BACKENDS = [
# 'django.contrib.auth.backends.ModelBackend'
'app.users.utils.UsernameMobileModelBackend',
]
# LOGIN_URL 的默认值是 : accounts/login/
# 我们只需要修改这个配置信息就可以,修改成 符合我们的路由就可以
LOGIN_URL = '/login/'
import re
from django.contrib.auth.backends import ModelBackend
from app.users.models import User
from django.http import JsonResponse
"""
封装/抽取的思想
为什么要封装/抽取?
1.降低代码的耦合度 (高内聚,低耦合)
2.提高代码的重用性 (很多地方都用到了重复的代码)
抽取/封装的步骤
1.定义一个函数(方法),把要抽取的代码复制过来
2.哪里有问题改哪里,没有的变量以参数的形式定义
3.验证抽取方法
什么时候进行抽取/封装
1. 某几行代码实现了一个小功能我们就可以抽取/封装
2. 我们的代码只要第二次重复使用就抽取/封装
"""
def get_user_by_username(username):
try:
if re.match(r'1[3-9]\d{9}', username):
# username 是手机号
user = User.objects.get(mobile=username)
else:
# username 是用户名
user = User.objects.get(username=username)
except User.DoesNotExist:
return None
return user
class UsernameMobileModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
# 1. 先查询用户
# username 有可能是 手机号 也有可能是用户名
# 通过对username进行正则来区分
user = get_user_by_username(username)
# 2. 判断用户的密码是否正确
if user is not None and user.check_password(password):
return user
from django.db import models
# Create your models here.
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
mobile=models.CharField(max_length=11,unique=True,verbose_name='手机号')
class Meta:
db_table = 'tb_users'
verbose_name = '用户'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
from django.shortcuts import render,redirect
from django.views import View
from app.users.models import User
from django import http
from django.urls import reverse
# 系统也能自己去帮助我们实现 登陆状态的保持
from django.contrib.auth import authenticate, login, logout
import re
import logging
logger = logging.getLogger('django')
class RegisterView(View):
def get(self,request):
return render(request,'register.html')
def post(self,request):
# 1.接收前端提交的用户名,密码和手机号
data = request.POST
username=data.get('username')
password=data.get('password')
password2=data.get('password2')
mobile=data.get('mobile')
# 2.数据的验证(我们不相信前端提交的任何数据)
# 2.1 验证必传(必须要让前端传递给后端)的数据是否有值
# all([el,el,el]) el必须有值 只要有一个为None 则为False
if not all([username,password,password2,mobile]):
return http.HttpResponseBadRequest('参数有问题')
# 2.2 判断用户名是否符合规则 判断 5-20位 数字 字母 _
if not re.match(r'[0-9a-zA-Z_]{5,20}',username):
return http.HttpResponseBadRequest('用户名不合法')
# 2.3 判断密码是否 符合规则
if not re.match(r'[0-9a-zA-Z_]{8,20}',password):
return http.HttpResponseBadRequest('密码不合法')
# 2.4 判断确认密码和密码是否一致
if password != password2:
return http.HttpResponseBadRequest('密码不一致')
# 2.5 判断手机号是否符合规则
if not re.match(r'1[3-9]\d{9}',mobile):
return http.HttpResponseBadRequest('手机号不符合规则')
# 2.6 验证同意协议是否勾选
# 3.验证数据没有问题才入库
# 当我们在操作外界资源(mysql,redis,file)的时候,我们最好进行 try except的异常处理
# User.objects.create 直接入库 理论是没问题的 但是 大家会发现 密码是明文
try:
user = User.objects.create_user(username=username,password=password,mobile=mobile)
except Exception as e:
logger.error(e)
return render(request,'register.html',context={'error_message':'数据库异常'})
# 4.返回响应, 跳转到首页
# 注册完成之后,默认认为用户已经登陆了
# 保持登陆的状态
# session
# 自己实现request.session
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
return redirect(reverse('contents:index'))
else:
return http.HttpResponse('注册失败')