加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

day83:luffy:添加购物车&导航栏购物车数字显示&购物车页

发布时间:2020-12-20 09:58:56 所属栏目:Python 来源:网络整理
导读:目录 1.添加购物车+验证登录状态 2.右上方购物车图标的小红圆圈数字 3.Vuex 4.购物车页面展示-后端接口 5.购物车页面展示-前端 6.解决一个购物车数量显示混乱的bug 1.添加购物车+验证登录状态 1.添加购物车的整体思想 购物车数据要存到redis中的 :要存用户i

目录

1.添加购物车+验证登录状态

2.右上方购物车图标的小红圆圈数字

3.Vuex

4.购物车页面展示-后端接口

5.购物车页面展示-前端

6.解决一个购物车数量显示混乱的bug

1.添加购物车+验证登录状态

1.添加购物车的整体思想

购物车数据要存到redis中的:要存用户id,课程id

用户在课程详情页面点击了加入购物车:

拿到当前课程的课程id 到数据库把课程id所对应的信息(需要在购物车显示的)加工成一个字典,然后json序列化成字符串保存到redis中

如何实现点击添加购物车,将购物车数据添加到redis中??????

2.添加购物车-后端接口

1.创建一个cart应用,并配置INSTALLAPP

python3 ../../ manage.py startapp cart

2.总路由中添加cart

# lyapi/urls.py
path('cart/',include("cart.urls") ),

3.cart/urls.py

from django.urls import path,re_path
from .  views

urlpatterns = [
    path(add_cart/post':add'}))

]

4.cart/views.py

from rest_framework.viewsets  Viewset
from django_redis  get_redis_connection
from course  models
from rest_framework.response  Response


class AddCartView(ViewSet):
    
    def add(self,request):
        course_id = request.data.get(course_id)
        user_id = 1  先把用户id写死
        
         去redis里存数据
        conn = get_redis_connection(cart)
        
         校验一下课程id是否合法
        try:
            models.Course.objects.get(id=course_id)
        except:
            return Response({msg课程不存在'},status=400)
      
        '''选择用集合的数据类型去存储'''
        conn.sadd(cart_%s' % user_id,course_id)
        
         vheader右方的购物车小红数字显示
        cart_length = conn.scard(' % user_id)  获取商品数量
        添加成功'cart_length
 dev.py
CACHES = {
    ......
    ":{
        BACKEND": django_redis.cache.RedisCache,LOCATIONredis://127.0.0.1:6379/3OPTIONS: {
            CLIENT_CLASSdjango_redis.client.DefaultClient
<!-- html -->
<div ="add-cart" @click="addCart"><img src="/static/img/cart-yellow.svg" alt="">加入购物车</div>

注意:添加购物车要验证用户是否已经登录

axios发送的是异步请求,setting.js里的check_login()函数和Detail.vue中的addCart是同步执行的,但是addCart添加购物车时需要验证登录状态的,

会出现:我这边还没有验证token呢,添加购物车那边就已经执行到检测token的代码位置了。

所以现在我们需要将两个请求变为同步请求,让token验证之后再进行别的操作

异步改成同步还是比较麻烦的,所以我们直接将验证token的操作写在addCart添加购物车方法里

// js     
addCart(){

         获取前端存储的token值
        let token = localStorage.token || sessionStorage.token;
       
         如果token值存在
        if (token){
          
           验证token
          this.$axios.post(`${this.$settings.Host}/users/verify/`,{
              token:token,}).then((res)=>{

           验证通过,可以添加购物车
            this.$settings.Host}/cart/add_cart/`,{
                 获取课程id
                course_id:this.course_id,1)">{
                 添加购物车成功,打印添加成功的信息
                .$message.success(res.data.msg);
              })
            验证没有通过(token错误或者token过期) 提示用户让用户去登录
            }).catch((error)=>{

              this.$confirm('您还没有登录!!!?','31s''取消'
              }).then(() => {
                this.$router.push('/user/login');
              })
              
               将过期的token清理掉
              sessionStorage.removeItem('token');
              sessionStorage.removeItem('username');
              sessionStorage.removeItem('id');
              localStorage.removeItem('token');
              localStorage.removeItem('username');
              localStorage.removeItem('id');
            })


        }
         token获取不到
        else {
          );
              })
        }



      },

2.右上方购物车图标的小红圆圈数字

我们在后端已经将购物车的长度返回了,在前端我们就可以拿到购物车的长度

 Detail.vue 
.$message.success(res.data.msg);
      
                  获取到后端发送过来的购物车长度
                 this.cart_length = res.data.cart_length
              })

现在就会有一个问题,我们这个cart_length数据属性是在Detail组件里面的,但是那个右上方购物车小红圆圈是在vheader组件里面的。不同组件之间的数据不是互通的

第一种思路:vheader组件是detail组件的子组件,我们可以通过vue的父子传值来实现。

那问题就来了

如果我们访问实战课页面 也就是/course,在course组件是不也要显示那个购物车小红圆圈?

但是在course组件我们根本就没有去获取购物车的长度。所以红圆圈数字根本显示不出来。所以父子传值这个思路行不通。

3.Vuex

因为对于一些数据,需要在多个组件中即时共享,所以根据上述的问题,我们引出vuex

1.安装Vuex

npm install -S vuex

2.把vuex注册到vue中

在src目录下创建store目录,并在store目录下创建一个index.js文件,index.js文件代码

 store/index.js
import Vue from 'vue'
import Vuex from 'vuex'


Vue.use(Vuex)

  export default new Vuex.Store({
  state: {  数据仓库,类似vue里面的data
    cart_length: 0  购物车数据
  },mutations: {  数据操作方法,类似vue里面的methods
    add_cart (state,cart_length) {
      state.cart_length = cart_length;  修改购物车的商品总数
    }
  }
})

3.挂载store对象

把上面index.js中创建的store对象注册到main.js的vue中。

 main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store';   引入


 Vue({
  el: '#app' 挂载
  components: { App },template: '<App/>'
})

4.Vheader组件读取store的数据(读取购物车长度)

在Vheader.vue头部组件中,直接就可以读取store里面的数据

router-link to="/">
    b>{{$store.state.cart_length}}="@/assets/shopcart.png"span>购物车 >
router-link>

5.Detail组件修改store的数据(修改购物车长度)

当用户点击添加购物车时,触发addCart中的post方法,将购物车的长度进行修改

{
    .$message.success(res.data.msg);
     从后端获取到的购物车长度不存在当前组件的数据属性中了,而是存到vuex中
    this.$store.commit('add_cart',res.data.cart_length) ;  commit用来触发mutation中声明的方法
})

6.关于页面刷新,vuex数据丢失问题

问题:vuex中的数据是存放在内存中的,页面一刷新,vuex中的数据就没有了

解决方式:用户点击刷新时,我们可以监听用户刷新的这个动作,可以在刷新之前对页面做一些动作。

当点击刷新时,我们先把数据存到sessionStorage或localStorage中,

页面刷新完成之后,再把数据取回来放到vuex中。这样的话就可以做到页面刷新了,数据也没有丢。

1.点击刷新,将数据存到sessionStorage中

 app.vue
<script>
export default {
  name: 'App' 页面刷新之前把cart_length数据存到了sessionStorage中
    window.addEventListener('beforeunload',()=>{
      console.log('页面要刷新啦!!!,赶紧保存数据!!!!');
      sessionStorage.setItem('cart_length',.$store.state.cart_length);

    })
  }
}
</script>

2..页面刷新完成之后,将数据从sessionStorage取出来放到vuex中

 vheader.vue
 created() {


    if (this.$store.state.cart_length === 0) {
      let cart_length = sessionStorage.getItem('cart_length');
      this.$store.commit('add_cart'

 utils/exceptions.py
from rest_framework.views  exception_handler

from django.db  DatabaseError
 Response
from rest_framework  status

from redis import RedisError  引入redis异常

 logging
logger = logging.getLogger(django)


 custom_exception_handler(exc,context):
    """
    自定义异常处理
    :param exc: 异常类
    :param context: 抛出异常的上下文
    :return: Response响应对象
    """
     调用drf框架原生的异常处理方法
    response = exception_handler(exc,context)

    if response is None:
        view = context[view']   错误出现的那个函数或者方法
        if isinstance(exc,DatabaseError) or isinstance(exc,RedisError):
             数据库异常/redis异常
            logger.error([%s] %s (view,exc))
            response = Response({message': 服务器内部错误'},status=status.HTTP_507_INSUFFICIENT_STORAGE)

    return response
redis的异常捕获以及记录错误日志

4.购物车页面展示-后端接口

1.添加购物车-课程有效期

1.在后端设置一个默认有效期

2.添加购物车时将有效期也存到redis中:之前的redis数据存储结构是集合,但是现在集合已经满足不了我们的需求了。要使用哈希数据类型存储

哈希数据类型结构如下所示:


        user_id:{
            course_id:expire,course_id:expire,}
        
'''
 cart/views.py


 AddCartView(ViewSet):

     有效期:表示永久有效
        存用户对应的课程id和有效期
        conn.hset(存放用户的购物车长度
        cart_length = conn.hlen( user_id)

          ......

在上面的代码中,我们可以看到一共建立了两次conn连接,这样并不是很好,所以我们借助一个redis的管道pipe

pipe = conn.pipeline()  创建管道
pipe.multi()

 将下面两个指令放到管道里面

pipe.hset(
cart_length = pipe.hlen( user_id)

pipe.execute()  执行上面两条指令

2.购物车列表-后端接口

 cart_list(self,request):
        user_id = 1   用户id先写死
        conn = get_redis_connection(')  获取cart对应的redis库对象
        
         将当前用户所对应的课程id从redis中取出来
        ret = conn.hgetall(' % user_id)   封装成了字典{课程id,有效期},dict {b'1': b'0',b'2': b'0'}
        cart_data_list = []
        for cid,eid in ret.items(): cid:课程id eid:有效期
                redis中存的是字节 所以要解码
                course_id = cid.decode(utf-8) 
                expire_id = eid.decode()

                course_obj = models.Course.objects.get(id=course_id)
               
               前端所需要的购物车数据包括
               1.课程名称
               2.课程封面图
               3.课程价格
               4.课程有效期
               so 我们自己创建一个数据结构去存储前端所需要的内容
               
                cart_data_list.append({
                    name:course_obj.name,1)">course_img':contains.SERVER_ADDR + course_obj.course_img.url,1)"> 图片路径是相对路径,我们将其变为绝对路径
                    price:course_obj.price,1)">expire_id:expire_id
                })
         Exception:
            logger.error(获取购物车数据失败)
            后台数据库出问题了,请联系管理员status.HTTP_507_INSUFFICIENT_STORAGE)

        将数据响应给前端
        xxxcart_data_list':cart_data_list})

5.购物车页面展示-前端

1.购物车前端的初始界面

...

2.将cart组件注册到路由上

import Vue from 'vue'
import Cart from '@/components/Cart'

Vue.use(Router)

export  Router({
  mode:'history'

3.关于cart组件和cartitem组件

在购物车页面中,整个购物车是一个组件(cart组件),然后要展示的每条购物车数据又是一个子组件(cartitem组件)

 cart.vue html部分 ="cart_course_list"CartItem v-for="(value,index) in cart_data_list" :key="index" :cart="value"></CartItem>  001 :cart 父组件往子组件传值 >
 cart.vue js部分
<script>
import CartItem from "./common/CartItem" {
    name: "Cart"return {
        cart_data_list:[],}
    },methods:{

    },created() {
    let token = sessionStorage.token || localStorage.token;
     (token){

      this.$axios.get(`${this.$settings.Host}/cart/add_cart/`) // 获取购物车数据
      .then((res)=>{
        this.cart_data_list = res.data.cart_data_list
      })
      ..$message.error(error.response.data.msg);
      })

    } {
      );
    }


  },components:{

      CartItem,}
}
</script>

父组件拿着自己的值 cart_data_list 传递给每个子组件进行渲染(父组件往子组件传值)

// cartitem.vue
template="cart_item">
      ="cart_column column_1">
        el-checkbox ="my_el_checkbox" v-model="checked"el-checkbox="cart_column column_2":src="cart.course_img"="/course/detail/1">{{cart.name}}="cart_column column_3"el-select v-model="cart.expire_id" size="mini" placeholder="请选择购买有效期" class="my_el_select">
          el-option label="1个月有效" value="30" key="30"el-option="2个月有效"="60"="60"="3个月有效"="90"="90"="永久有效"="0"="0"el-select="cart_column column_4">¥{{cart.price}}>删除>

script>
export default {
    name: "CartItemreturn {
        checked:false'cart// 002:子组件接受父组件传过来的值
}
>

6.解决一个购物车数量显示混乱的bug

1.页面刷新导致的vuex数据重置

解决方法:页面刷新前将数据存到SessionStorage

 App.vue
<script>{
  sessionStorage.setItem('cart_length',1)">.$store.state.cart_length);
    })
  }
}
</script>

2.不同页面显示的购物车小红圆圈数量不一致

在组件加载的时候,会执行vheader中的created方法,拿到sessionStorage的值

let cart_length = sessionStorage.getItem('cart_length');

?

created(){
    this.$store.state.cart_length === 0){  如果购物车没有数据
      let cart_length = sessionStorage.getItem('cart_length');  就去sessionStorage中拿数据
       并将数据存放到vuex中
    }
  },

?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读