运行前端项目

进入前台项目的根目录
然后安装依赖
在前端项目根目录cmd命令框安装
npm install
启动项目
npm run serve

用户表设计

创建表的准备工作

在diango项目中的settings.py文件中配置mysql数据库相关信息

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST':"localhost",
        "PORT":3306, 	#端口号
        'USER':'root',
        'PASSWORD':'数据库密码',
        'NAME':'数据库名'
    }
}

然后在_init_文件安装数据库

import pymysql
pymysql.install_as_MySQLdb()

在diango项目子应用中的models.py文件中编写模型类
用户表: 用户名、密码、手机号

from django.db import models
# Create your models here.
class User(models.Model):
    username=models.CharField(max_length=32,unique=True,verbose_name='用户名')
    password=models.CharField(max_length=32,verbose_name='密码')
    mobile=models.CharField(max_length=16,verbose_name='手机号')
    class Meta:
        verbose_name='用户表'
        verbose_name_plural=verbose_name
    def __str__(self):
        return "%s (%s)"%(self.username,self.mobile)

生成迁移文件
python manage.py makemigrations
进行迁移
python manage.py migrate

编写视图类

from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from users.models import User
from django.http import HttpResponse
import re,random
# Create your views here.
# 检测用户名长度,是否重复
class CheckUsernameview(APIView):
    def get(self,request,username):
        if not username:
            return Response({
                'code':400,
                'msg':'用户名错误'
            })
        if not (6<= len(username) <=32):
            return Response({
                'code': 400,
                'msg': '用户长度不符合'
            })
        user_count = User.objects.filter(username=username).count()
        if  user_count:
            #user_count不为0,道标数据库有这条数据
            return Response({
                'code':400,
                'msg':'用户名已存在'
            })
        return Response({
            'code':200,
            'msg':'用户名可用'
        })
# 检测手机号是否符合标准,重复
class CheckMobile(APIView):
    def get(self,request,mobile):
        rule=r'^1[3-9][0-9]{9}$'  #定义手机号正则
        rs =re.findall(rule,mobile)  #返回结果是一个列表 如果匹配不到 返回的是空列表
        if not rs:
            return Response({
                'code':400,
                'msg':'手机号格式不对'
            })
        #程序走到这一步说明手机号格式没问题
        mobile_count=User.objects.filter(mobile=mobile).count()
        if mobile_count:
            return Response({
                'code':400,
                'msg':'手机号已存在'
            })
        return Response({
            'code':200,
            'msg':'手机号可用'
        })
# 检测密码是否符合标准
class Checkpassword(APIView):
    def post(self,request):
        pwd=request.data.get('pwd')  #接收前台传过来的密码
        #检验密码长度
        if not (6<=len(pwd)<=32):
            return Response({
                'code':400,
                'msg':'密码长度不匹配'
            })
        return Response({
            'code':200,
            'msg':'密码可用'
        })

#检测再次输入密码
class CheckPasswordReview(APIView):
    def post(self,request):
        pwd=request.data.get('pwd')
        pwd_re=request.data.get('pwd_re')
        if pwd!=pwd_re:
            return Response({
                'code':400,
                'msg':'密码不一致'
            })
        return Response({
            'code':200,
            'msg':'密码一致'
        })
# 生成验证码图片,并将验证码保存到redis数据库
class Verimageview(APIView):
    def get(self,request,uuid):
        #1.生成验证码所生产的字符串
        code=str(random.randint(1000,9999))

        #根据字符串变成图片   #要在项目终端进行安装pip install captcha
        from captcha.image import ImageCaptcha  #导包
        img=ImageCaptcha() #实例化验证码的类
        img_pic=img.generate(code) #生成器生成验证码图片
        print('生成的图片',img_pic) #返回是一个IO字节流

        #把验证码存到redis
        import redis    #导包
        r=redis.Redis(host='127.0.0.1',port=6379,password='redis库密码')
        r.set(uuid,code,ex=60*5)  #生效时间5分钟
        print(uuid)
        print(code)
        # return Response(img_pic)
        return HttpResponse(img_pic,content_type='image/png')

#输入验证码的类试图
class CheckCodeView(APIView):
    def post(self,request):
        code=request.data.get('code') #用户输入验证码
        uuid=request.data.get('uuid') #用户唯一标志

        #1,链接数据库,取出uuid对应的验证码
        import redis    #导包
        r=redis.Redis(host='127.0.0.1',port=6379,password='redis库密码')
        sys_code=r.get(uuid)
        #如果uuid对应的数据为空的话,说明验证码已过期
        if not sys_code:
            return Response({
                'code':400,
                'msg':'验证密码已过期'
            })
        #将数据库返回的byte类型的数据,转换为字符串类型
        sys_code_str=sys_code.decode()
        #2.用户输入的验证码和数据库的验证码做比对
        if sys_code_str!=code:
            #如果不一致,验证码错误
            return Response({
                'code':400,
                'msg':'验证码错误'
            })
        #如果一致,说明验证码通过
        return Response({
            'code':200,
            'msg':'验证通过'
        })

# 注册的类试图
class RegView(APIView):
    def post(self,request):
        username=request.data.get('username')
        password=request.data.get('password')
        mobile=request.data.get('mobile')
        agree=request.data.get('agree')
        #判断一下用户是否勾选协议
        if not int(agree):   #转int是因为字符串的零不可以用not 求判断
            return Response({
                'code':400,
                'msg':'协议没勾选'
            })
        if not username or not password or not mobile:
            return Response({
                'code':400,
                'msg':'参数输入有误'
            })
        # TOOO 调研用户名,密码手机号
        #校验完毕 写入数据库
        try:
            User.objects.create(
                username=username,
                password=password,
                mobile=mobile
            )
            return Response({
                'code':200,
                'msg':'注册成功'
            })
        except Exception as a:
            return Response({
                'code':400,
                'msg':'注册失败'
            })

配置路由

路由分发
在子应用创建一个同名文件进行分发

from django.contrib import admin
from django.urls import path,include
from users import urls
urlpatterns = [
    path('admin/', admin.site.urls),
    path('user/',include(urls)),
]

配置路由

# from django.contrib import admin
from django.urls import path
from users import views
urlpatterns = [
    # path('admin/', admin.site.urls),
    path('cher/username/<str:username>/',views.CheckUsernameview.as_view()),
    path('check/mobile/<str:mobile>/',views.CheckMobile.as_view()),
    path('check/password/',views.Checkpassword.as_view()),
    path('check/password_re/',views.CheckPasswordReview.as_view()),
    path('check/image/<str:uuid>/',views.Verimageview.as_view()),
    path('check/img/code/',views.CheckCodeView.as_view()),
    path('reg/',views.RegView.as_view())
]

路由配置好后使用ApiPost来检测接口是否成功

前端

1.先在前端项目安装 npm install
然后找到注册相关的vue文件
对相关的功能进行联调

data(){
	// 用户名的校验方法
    let validateName = (rule, value, callback) => {
      console.log("校验用户名,规则", rule, "用户名", value, "回调函数", callback)
      // TODO 校验用户名
      // 失败 return callback(new Error("字母开头,长度5-16之间,允许字母数字下划线"));
      // 成功 return callback();
      if (!value){
        return
      }
      this.$axios.get("/user/cher/username/"+value+'/').then(res=>{
        if (res.data.code==200){
          return callback()
        }else{
          return callback(new Error(res.data.msg))
        }
      }).catch(err=>{
        console.log(err)
        alert('报错了')
      })
    };
    // 手机号的校验方法
    let validateMobile = (rule, value, callback) => {
      console.log("校验手机号,规则", rule, "手机号", value, "回调函数", callback)
      // TODO 校验手机号
      // 失败 return callback(new Error("字母开头,长度5-16之间,允许字母数字下划线"));
      // 成功 return callback();
      if (!value){
        return
      }
      this.$axios.get("/user/check/mobile/"+value+'/').then((result) => {
        if (result.data.code==200){
          return callback();
        }else{
          return callback(new Error(result.data.msg));
        }
      }).catch((err) => {
        console.log(err)
        alert('手机号报错')
      });
    };
    // 密码的校验方法
    let validatePass = (rule, value, callback) => {
      console.log("校验密码,规则", rule, "密码", value, "回调函数", callback)
      // TODO 校验密码
      // 失败 return callback(new Error("字母开头,长度5-16之间,允许字母数字下划线"));
      // 成功 return callback();
      if (!value){
        return
      }
      this.$axios.post('/user/check/password/',{'pwd':value}).then((result) => {
        if (result.data.code==200){
          return callback();
        }else{
          return callback(new Error(result.data.msg));
        }
      }).catch((err) => {
        console.log(err)
        alert('密码报错')
      });
    };
    // 确认密码的校验方法
    let validateConfirmPass = (rule, value, callback) => {
      console.log("校验确认密码,规则", rule, "二次输入的密码", value, "回调函数", callback)
      // TODO 校验确认密码
      // 失败 return callback(new Error("字母开头,长度5-16之间,允许字母数字下划线"));
      // 成功 return callback();
      this.$axios.post('/user/check/password_re/',{
        'pwd':this.RegisterUser.pass,
        'pwd_re':value,
      }).then((result) => {
        if (result.data.code==200){
          return callback()
        }else{
          return callback(new Error(result.data.msg));
        }
      })
    };
    // 校验图片验证码
    let validateImageCode = (rule, value, callback) => {
      console.log("校验验证码,规则", rule, "二验证码", value, "回调函数", callback)
      // TODO 校验验证码
      // 失败 return callback(new Error("字母开头,长度5-16之间,允许字母数字下划线"));
      // 成功 return callback();
      this.$axios.post('/user/check/img/code/',{
        'uuid':this.imageCodeID,
        'code':value,
      }).then((result) => {
        if(result.data.code==200){
          return callback()
        }else{
          return callback(new Error(result.data.msg))
        }
      }).catch((err) => {
        console.log(err)
        alert('验证错误')
      });
},
  methods: {

    // 生成图片验证码地址
    genImageCode() {
      // 生成一个uuid
      this.imageCodeID = uuid4() //uuid理解成随机字符串,就是用来标记你是谁
      console.log(this.imageCodeID)
      // 生成一个图片验证码地址    ///////修改一下后端生成图片的路由/////
      this.iamgeCodeUrl = "/user/check/image/" + this.imageCodeID + "/"
      console.log(this.iamgeCodeUrl)
    },

    // 用户注册
    Register() {
      // 是否同意用户协议
      if (!this.aggree) {
        this.flag = true
        return
      }
      // 已勾选,则不显示提示信息
      this.flag = false
      // 通过element自定义表单校验规则,校验用户输入的用户信息
      this.$refs["ruleForm"].validate((valid) => {
        if (valid) {
          // TODO 注册用户
          this.$axios.post('/user/reg/',{
            username:this.RegisterUser.name,
            password:this.RegisterUser.pass,
            mobile:this.RegisterUser.mobile,
            agree:this.aggree,
          }).then((result) => {
            if (result.data.code==200){
              // alert('注册成功')
              // 清空注册输入的内容
              this.RegisterUser.name=''
              this.RegisterUser.pass=''
              this.RegisterUser.mobile=''
              this.RegisterUser.confirmPass=''
              this.RegisterUser.imageCode=''
              this.aggree=false
              // 关闭弹窗
              this.isRegister=false
              this.notifySucceed(result.data.msg)
            }else{
              // alert('注册失败')
              this.notifyError(result.data.msg)
            }
          }).catch((err) => {
            console.log(err)
            alert('页面报错了')
          });
        } else {
          return false;
        }
      });
    },
  },