DAY 82 vue06

1 前端配置请求后端的地址
2 meida的配置
-media_url
3 前端登录功能
-判断用户名密码是否为空,message的提示
   -发送axios请求(post)
4 前端存储(三个位置)

5 前端用户名的显示与不显示

6 发送短信(腾讯云)
-api和sdk
   -发送短信的2.0的sdk
   -封装了一层(单独做成一个模块,以后可以顺利的移到任何其他项目中)
7 校验手机号是否存在的接口

8 限制短信发送频率的频率类

1 手机号登录接口

1 只需要手机号和验证码,post

views.py

    @action(methods=['POST'], detail=False)
   def login_phone(self, request, *args, **kwargs):

       # 序列化类
       ser = UserPhoneModelSerializer(data=request.data)
       ser.is_valid(raise_exception=True)
       token = ser.context['token']
       user = ser.context['user']
       return APIResponse(token=token, username=user.username, id=user.id)

 

serializer.py

from django.core.cache import cache
from django.conf import settings


class UserPhoneModelSerializer(serializers.ModelSerializer):
   # 需要重写code
   code = serializers.CharField()
   mobile = serializers.CharField(max_length=11)

   class Meta:
       model = models.User
       fields = ['mobile', 'code']

   # 写全局钩子(校验手机号和验证码是否正确,登录成功,签发token)
   def validate(self, attrs):

       mobile = attrs.get('mobile')
       code = attrs.get('code')
       # 从缓存中取出这个手机号对应的验证码
       cache_code = cache.get(settings.SMS_PHONE_CACHE % mobile)
       if cache_code and cache_code == code:
           # 可以登录,根据手机号,查到用户,给这个用户签发token
           user = models.User.objects.get(mobile=mobile)
           # 签发token
           payload = jwt_payload_handler(user)
           token = jwt_encode_handler(payload)
           self.context['token'] = token
           self.context['user'] = user
           return attrs

       else:
           raise ValidationError('验证码错误')

 

2 前端获取验证码,手机号登录,前端注册功能

Register.vue

<template>
   <div class="register">
       <div class="box">
           <i class="el-icon-close" @click="close_register"></i>
           <div class="content">
               <div class="nav">
                   <span class="active">新用户注册</span>
               </div>
               <el-form>
                   <el-input
                           placeholder="手机号"
                           prefix-icon="el-icon-phone-outline"
                           v-model="mobile"
                           clearable
                           @blur="check_mobile">
                   </el-input>
                   <el-input
                           placeholder="密码"
                           prefix-icon="el-icon-key"
                           v-model="password"
                           clearable
                           show-password>
                   </el-input>
                   <el-input
                           placeholder="验证码"
                           prefix-icon="el-icon-chat-line-round"
                           v-model="sms"
                           clearable>
                       <template slot="append">
                           <span class="sms" @click="send_sms">{{ sms_interval }}</span>
                       </template>
                   </el-input>
                   <el-button type="primary" @click="register">注册</el-button>
               </el-form>
               <div class="foot">
                   <span @click="go_login">立即登录</span>
               </div>
           </div>
       </div>
   </div>
</template>

<script>
   export default {
       name: "Register",
       data() {
           return {
               mobile: '',
               password: '',
               sms: '',
               sms_interval: '获取验证码',
               is_send: false,
          }
      },
       methods: {
           close_register() {
               this.$emit('close', false)
          },
           go_login() {
               this.$emit('go')
          },
           check_mobile() {
               if (!this.mobile) return;
               if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
                   this.$message({
                       message: '手机号有误',
                       type: 'warning',
                       duration: 1000,
                       onClose: () => {
                           this.mobile = '';
                      }
                  });
                   return false;
              }
               this.is_send = true;


               //校验手机号如果存在就不用注册,直接去登录
               this.$http.get(this.$BASE_URL + 'user/check_phone/', {params: {phone: this.mobile}}).then(res => {
                   console.log(res.data)
                   if (res.data.code == 100) {
                       this.is_send = false;

                       this.$message({
                           message: '该账号已经存在,请直接去登录',
                           type: 'success',
                      })
                       this.is_send = true;
                  } else {
                       this.is_send = true;
                       this.$message({
                           message: '可以正常注册',
                           type: 'warning',
                      })
                  }
              })
          },
           register() {
               if(!(this.mobile &&this.sms && this.password)){
                   this.$message({
                           message: '手机号,验证码,密码不能为空',
                           type: 'error',
                      })
                   return
              }
               this.$http.post(this.$BASE_URL + 'user/register/', {
                   mobile: this.mobile,
                   code: this.sms,
                   password: this.password
              }).then(res => {
                   if (res.data.code == 100) {
                       this.$message({
                           message: '注册成功,请去登录',
                           type: 'success',
                      })
                       //关掉注册框,打开登录框
                       this.go_login()
                  } else {
                       this.$message({
                           message: '注册失败,请稍后再试',
                           type: 'error',
                      })
                  }
              })

          },
           send_sms() {
               if (!this.is_send) return;
               this.is_send = false;
               let sms_interval_time = 60;
               this.sms_interval = "发送中...";
               let timer = setInterval(() => {
                   if (sms_interval_time <= 1) {
                       clearInterval(timer);
                       this.sms_interval = "获取验证码";
                       this.is_send = true; // 重新回复点击发送功能的条件
                  } else {
                       sms_interval_time -= 1;
                       this.sms_interval = `${sms_interval_time}秒后再发`;
                  }
              }, 1000);

               this.$http.get(this.$BASE_URL + 'user/send_sms/?phone=' + this.mobile).then(res => {
                   console.log(res.data)
                   if (res.data.code == 100) {
                       this.$message({
                           message: '短信发送成功',
                           type: 'success',
                      })
                  } else {
                       this.$message({
                           message: '短信发送失败,请稍后再试。。。',
                           type: 'error',
                      })
                  }
              })


          }
      }
  }
</script>

<style scoped>
  .register {
       width: 100vw;
       height: 100vh;
       position: fixed;
       top: 0;
       left: 0;
       z-index: 10;
       background-color: rgba(0, 0, 0, 0.3);
  }

  .box {
       width: 400px;
       height: 480px;
       background-color: white;
       border-radius: 10px;
       position: relative;
       top: calc(50vh - 240px);
       left: calc(50vw - 200px);
  }

  .el-icon-close {
       position: absolute;
       font-weight: bold;
       font-size: 20px;
       top: 10px;
       right: 10px;
       cursor: pointer;
  }

  .el-icon-close:hover {
       color: darkred;
  }

  .content {
       position: absolute;
       top: 40px;
       width: 280px;
       left: 60px;
  }

  .nav {
       font-size: 20px;
       height: 38px;
       border-bottom: 2px solid darkgrey;
  }

  .nav > span {
       margin-left: 90px;
       color: darkgrey;
       user-select: none;
       cursor: pointer;
       padding-bottom: 10px;
       border-bottom: 2px solid darkgrey;
  }

  .nav > span.active {
       color: black;
       border-bottom: 3px solid black;
       padding-bottom: 9px;
  }

  .el-input, .el-button {
       margin-top: 40px;
  }

  .el-button {
       width: 100%;
       font-size: 18px;
  }

  .foot > span {
       float: right;
       margin-top: 20px;
       color: orange;
       cursor: pointer;
  }

  .sms {
       color: orange;
       cursor: pointer;
       display: inline-block;
       width: 70px;
       text-align: center;
       user-select: none;
  }
</style>

Login.vue

<template>
   <div class="login">
       <div class="box">
           <i class="el-icon-close" @click="close_login"></i>
           <div class="content">
               <div class="nav">
                   <span :class="{active: login_method === 'is_pwd'}"
                         @click="change_login_method('is_pwd')">密码登录</span>
                   <span :class="{active: login_method === 'is_sms'}"
                         @click="change_login_method('is_sms')">短信登录</span>
               </div>
               <el-form v-if="login_method === 'is_pwd'">
                   <el-input
                           placeholder="用户名/手机号/邮箱"
                           prefix-icon="el-icon-user"
                           v-model="username"
                           clearable>
                   </el-input>
                   <el-input
                           placeholder="密码"
                           prefix-icon="el-icon-key"
                           v-model="password"
                           clearable
                           show-password>
                   </el-input>
                   <el-button type="primary" @click="pwd_login">登录</el-button>
               </el-form>
               <el-form v-if="login_method === 'is_sms'">
                   <el-input
                           placeholder="手机号"
                           prefix-icon="el-icon-phone-outline"
                           v-model="mobile"
                           clearable
                           @blur="check_mobile">
                   </el-input>
                   <el-input
                           placeholder="验证码"
                           prefix-icon="el-icon-chat-line-round"
                           v-model="sms"
                           clearable>
                       <template slot="append">
                           <span class="sms" @click="send_sms">{{ sms_interval }}</span>
                       </template>
                   </el-input>
                   <el-button type="primary" @click="phone_login">登录</el-button>
               </el-form>
               <div class="foot">
                   <span @click="go_register">立即注册</span>
               </div>
           </div>
       </div>
   </div>
</template>

<script>
   export default {
       name: "Login",
       data() {
           return {
               username: '',
               password: '',
               mobile: '',
               sms: '',
               login_method: 'is_pwd',
               sms_interval: '获取验证码',
               is_send: false,
          }
      },
       methods: {
           close_login() {
               this.$emit('close')
          },
           go_register() {
               this.$emit('go')
          },

           //密码登录方法
           pwd_login() {
               if (!(this.username && this.password)) {
                   //用户名或密文为空
                   this.$message({
                       message: '用户名或密码不能为空',
                       type: 'warning'
                  });

              } else {
                   //发送axios请求
                   this.$http.post(this.$BASE_URL + 'user/login/', {
                       username: this.username,
                       password: this.password
                  }).then(res => {
                       console.log(res)
                       if (res.data.code == 100) {
                           //登录成功

                           //1 存储返回的token,username(可以存的地方有三个)
                           //咱们放到cookie中(放到cookie中)
                           this.$cookies.set('token', res.data.token, '7d')
                           this.$cookies.set('username', res.data.username, '7d')
                           // sessionStorage.setItem()
                           // sessionStorage.getItem()
                           // localStorage.setItem()
                           // localStorage.getItem()
                           //2 销毁框
                           this.close_login()


                      } else {
                           this.$message({
                               message: res.data.msg,
                               type: 'warning'
                          });
                      }
                  })
              }

          },

           //手机号登录
           phone_login() {
               if (!(this.mobile && this.sms)) {
                   //用户名或密文为空
                   this.$message({
                       message: '手机号或验证码不能为空',
                       type: 'warning'
                  });

              } else {
                   //发送axios请求
                   this.$http.post(this.$BASE_URL + 'user/login_phone/', {
                       mobile: this.mobile,
                       code: this.sms
                  }).then(res => {
                       console.log(res)
                       if (res.data.code == 100) {
                           //登录成功
                           this.$cookies.set('token', res.data.token, '7d')
                           this.$cookies.set('username', res.data.username, '7d')
                           this.close_login()

                      } else {
                           this.$message({
                               message: res.data.msg,
                               type: 'warning'
                          });
                      }
                  })
              }

          },
           change_login_method(method) {
               this.login_method = method;
          },
           check_mobile() {
               if (!this.mobile) return;  //如果手机号没填,这个方法结束了
               //js的正则   字符串.match('/正则表达式/')
               if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
                   this.$message({
                       message: '手机号有误',
                       type: 'warning',
                       duration: 1000,  //message的显示时间
                       onClose: () => {
                           this.mobile = '';  //把手机号清空
                      },

                  });
                   return false;
              }

               //前端输入的手机号是正确手机号,去后端,查看手机号是否存在

               // this.$http.get(this.$BASE_URL+'user/check_phone/?phone='+this.mobile)
               this.$http.get(this.$BASE_URL + 'user/check_phone/', {params: {phone: this.mobile}}).then(res => {
                   console.log(res.data)
                   if (res.data.code == 100) {
                       //正常的,可以发送验证码,如果点击发送验证码按钮,就能点击,否则为false,就不能点击
                       this.$message({
                           message: '该手机可以发送验证码',
                           type: 'success',
                      })
                       this.is_send = true;
                  } else {
                       this.is_send = false;
                       this.mobile = ''
                       this.$message({
                           message: res.data.msg,
                           type: 'warning',
                      })
                  }
              })


          },
           send_sms() {

               if (!this.is_send) return;
               this.is_send = false;
               let sms_interval_time = 60;
               this.sms_interval = "发送中...";
               let timer = setInterval(() => {
                   if (sms_interval_time <= 1) {
                       clearInterval(timer);
                       this.sms_interval = "获取验证码";
                       this.is_send = true; // 重新回复点击发送功能的条件
                  } else {
                       sms_interval_time -= 1;
                       this.sms_interval = `${sms_interval_time}秒后再发`;
                  }
              }, 1000);
               //向后端发送短信接口发请求,给这个手机号发短信
               this.$http.get(this.$BASE_URL + 'user/send_sms/?phone=' + this.mobile).then(res => {
                   console.log(res.data)
                   if (res.data.code == 100) {
                       this.$message({
                           message: '短信发送成功',
                           type: 'success',
                      })
                  } else {
                       this.$message({
                           message: '短信发送失败,请稍后再试。。。',
                           type: 'error',
                      })
                  }
              })
          }
      }
  }
</script>

<style scoped>
  .login {
       width: 100vw;
       height: 100vh;
       position: fixed;
       top: 0;
       left: 0;
       z-index: 10;
       background-color: rgba(0, 0, 0, 0.3);
  }

  .box {
       width: 400px;
       height: 420px;
       background-color: white;
       border-radius: 10px;
       position: relative;
       top: calc(50vh - 210px);
       left: calc(50vw - 200px);
  }

  .el-icon-close {
       position: absolute;
       font-weight: bold;
       font-size: 20px;
       top: 10px;
       right: 10px;
       cursor: pointer;
  }

  .el-icon-close:hover {
       color: darkred;
  }

  .content {
       position: absolute;
       top: 40px;
       width: 280px;
       left: 60px;
  }

  .nav {
       font-size: 20px;
       height: 38px;
       border-bottom: 2px solid darkgrey;
  }

  .nav > span {
       margin: 0 20px 0 35px;
       color: darkgrey;
       user-select: none;
       cursor: pointer;
       padding-bottom: 10px;
       border-bottom: 2px solid darkgrey;
  }

  .nav > span.active {
       color: black;
       border-bottom: 3px solid black;
       padding-bottom: 9px;
  }

  .el-input, .el-button {
       margin-top: 40px;
  }

  .el-button {
       width: 100%;
       font-size: 18px;
  }

  .foot > span {
       float: right;
       margin-top: 20px;
       color: orange;
       cursor: pointer;
  }

  .sms {
       color: orange;
       cursor: pointer;
       display: inline-block;
       width: 70px;
       text-align: center;
       user-select: none;
  }
</style>

 

3 后端注册接口

1 前端传入是不带用户名的,我们可以自动生成一个用户名,或者使用手机号作为用户(咱们)
2 邮箱也没传入(邮箱可以为空)
3 前端出入
-手机号
   -密码
   -code(表中没有)
4 post请求

views.py

    @action(methods=['POST'], detail=False)
   def register(self, request, *args, **kwargs):
       # 序列化类
       ser = UserRegisterModelSerializer(data=request.data)
       ser.is_valid(raise_exception=True)
       ser.save() # 新增会触发,serializer的create方法,重写create方法
       return APIResponse(code=100,msg='注册成功')

serializer.py

class UserRegisterModelSerializer(serializers.ModelSerializer):
code = serializers.CharField(write_only=True)

class Meta:
model = models.User
fields = ['mobile', 'code', 'password']

# # code这个字段只用来写
# extra_kwargs = {
# 'code': {'write_only': True}
# }

# 可给手机号和password加局部校验钩子
def validate_mobile(self, data):
import re
if re.match('^1[3-9][0-9]{9}$', data):
return data
else:
raise ValidationError('手机号不合法')

def validate(self, attrs):
mobile = attrs.get('mobile')
code = attrs.get('code')
# 校验code是否是我们给的
# 从缓存中取出这个手机号对应的验证码
cache_code = cache.get(settings.SMS_PHONE_CACHE % mobile)
if cache_code and cache_code == code:
# 可以注册
# 如何注册?需要重写create,由于密码是密文,需要重写,使用create_user来创建用户
# 把code剔除
attrs.pop('code')
# 加入username
attrs['username'] = mobile
return attrs
else:
raise ValidationError('验证码错误')

def create(self, validated_data):
# validated_data:username,password,mobile (email,icon都可以为空)
user = models.User.objects.create_user(**validated_data)
return user

 

##

5 redis介绍安装

1 redis数据库,非关系型(redis:内存数据库,所有数据放在内存中,mongodb:数据放在硬盘上,es:放在硬盘上)
2 关系型:mysql,db2,oracle,posgresql,sqlserver,达梦(国产数据),sql都是通用的,表和表之间的关联关系,事务的支持比较好,锁机制


3 redis是一个key-value存储系统。
-key-value存储
-支持5大数据类型:字符串,列表,字典(hash),集合,有序集合
-6.0之前单线程,单进程的
-redis是单线程为什么这么快?
-全内存操作
-基于io多路复用的模型
-没有多线程多进程的切换
-性能高,单机qps高达10w,实际生产环境实际6w
-可以持久化
-c语言写的
4 Memcached:内存数据库,key-value存储,支持的数据类型少,只有str类型,没有持久化,断电消失

5 redis不支持windows,io多路复用的模型,在linux使用的是epoll,在windwos上没有epoll,于是有一些第三方,基于源码改动了一些,让他可以在windows上执行(最新版只到3.x)
6 windows的下载地址
-https://github.com/microsoftarchive/redis/releases
7 windows安装
-一路下一步:添加到环境变量,端口号是6379,使用的最大内存,不限制

8 装完之后,就会有个redis服务
-通过启动服务,停止服务来运行停止redis
9 命令方式启动和停止
-启动
redis-server 配置文件路径 # 使用配置文件启动
redis-server # 不使用配置文件启动
-客户端连接
redis-cli # 连接上本地 127.0.0.1 6379
redis-cli -h 127.0.0.1 -p 6378
在客户端:shutdown
在客户端敲:ping 回一个pone
10 redis的客户端很多
-redis-desktop-manager
-qt:平台,专门用来写图形化介模
-pyqt:用python代码在qt平台写图形化界面

11 在客户端写
set name lqz
get name

 

6 python操作redis之普通连接和连接池

# pip install redis

# redis之普通连接
# from redis import Redis
# conn = Redis(host='127.0.0.1',port=6379) # 什么都不写,连的就是本地的6379
# # 获取name这个key对应的值
# res=conn.get('name')
# print(res)
# conn.close()

# redis连接之连接池

import redis
# 先定义一个池子,池子大小指定
# 这个pool必须做成一个单例(这句话只写一次)
#
# pool = redis.ConnectionPool(max_connections=10)

# 当该py文件以脚本运行,其中包的导入不能使用相对导入
# 如果是以模块形式导入使用,这个模块内可以使用相对导入

from redis_pool import POOL #天然的单例,不管导入多少次,只会实例化一次
# 建立连接,从池子中获取一个连接
conn=redis.Redis(connection_pool=POOL)

res=conn.get('name')
print(res)

 

7 字符串操作


from redis import Redis
conn = Redis(host='127.0.0.1',port=6379) # 什么都不写,连的就是本地的6379

# 1 设置值
# conn.set('age',16)
# conn.set('name','刘清政')
# conn.set('hobby','篮球')
# conn.set('hobby','篮球',ex=3,nx=True)
# conn.set('hobby','足球',ex=3,nx=True)
# conn.set('hobby','足球',xx=True)
# conn.set('hobby1','足球',xx=True)
'''
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
'''

# 2 取值
# print(str(conn.get('name'),encoding='utf-8')) #取出来的值是bytes格式,以utf-8形式


# 3 setnx

# 4 setex
# conn.setex('xx',5,'yy')

#5 psetex
# conn.psetex('xx',5000,'yy')

#6 mset 批量设置

# conn.mset({'name':'lqz','age':19})

# 7 mget(keys, *args)
# print(conn.mget(['name','age']))
# print(conn.mget('name','age'))

#8 getset(name, value)
# res=conn.getset('name','egon')

#9 getrange


# gbk: 2个字节表示一个字符
# utf-8 3个字节表示一个字符
# res=conn.getrange('name',0,0) # 前闭后闭区间
# res=conn.getrange('name',0,2).decode('utf-8') # 前闭后闭区间
# print(res)


# 10 setrange
# conn.setrange('name',2,'zzz')

# 11 strlen 一个汉字,是3个字节
# print(conn.strlen('name'))


# 12 incr
# print(conn.incr('age'))


# 13 decr
# conn.decr('age')

# 14 append
conn.append('xxxxxxx','nb')



# print(res)
conn.close()
posted @ 2021-06-17 16:14  DEJAVU_ERIC  阅读(35)  评论(0编辑  收藏  举报