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

day84:luffy:优惠活动策略&用户认证&购物车商品的勾选/

发布时间:2020-12-20 09:58:52 所属栏目:Python 来源:网络整理
导读:目录 1.课程列表页活动和真实价格计算 1.优惠活动策略的model表结构 2.课程列表页显示优惠类型名称 3.课程列表页显示真实价格 4.将优惠类型名称和真实价格显示到前端页面上 5.课程列表页显示具体结束时间 2.添加购物车/查看购物车的用户认证 3.购物车商品价

目录

1.课程列表页活动和真实价格计算

  1.优惠活动策略的model表结构

  2.课程列表页显示优惠类型名称

  3.课程列表页显示真实价格

  4.将优惠类型名称和真实价格显示到前端页面上

  5.课程列表页显示具体结束时间

2.添加购物车/查看购物车的用户认证

3.购物车商品价格的勾选/结算

  1.每个课程的真实价格显示到购物车页面上

  2.勾选/非勾选应在redis中实时存储-后端接口

  3.勾选/非勾选应该在前端页面重新计算价格

  4.购物车列表显示-后端接口

1.课程列表页活动和真实价格计算

既然提到了活动,那与之对应的肯定是优惠策略、优惠活动等等。

所以我们要为优惠活动策略单独建立表结构

1.优惠活动策略的model表结构

class CourseDiscountType(BaseModel):
    """课程优惠类型"""
    name = models.CharField(max_length=32,verbose_name="优惠类型名称")
    remark = models.CharField(max_length=250,blank=True,null=True,1)">备注信息)

     Meta:
        db_table = ly_course_discount_type
        verbose_name = 
        verbose_name_plural = "

    def __str__(self):
        return %s" % (self.name)


 CourseDiscount(BaseModel):
    课程优惠模型
    discount_type = models.ForeignKey(CourseDiscountType",on_delete=models.CASCADE,related_name='coursediscounts',1)">优惠类型)
    condition = models.IntegerField(blank=True,default=0,1)">满足优惠的价格条件设置参与优惠的价格门槛,表示商品必须在xx价格以上的时候才参与优惠活动,<br>如果不填,则不设置门槛") #因为有的课程不足100,你减免100,还亏钱了
    sale = models.TextField(verbose_name=优惠公式
    不填表示免费;<br>
    *号开头表示折扣价,例如*0.82表示八二折;<br>
    -号开头则表示减免,例如-20表示原价-20;<br>
    如果需要表示满减,则需要使用 原价-优惠价格,例如表示课程价格大于100,优惠10;大于200,优惠25,格式如下:<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;满100-10<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;满200-25<br>
    ly_course_discount价格优惠策略价格优惠:%s,优惠条件:%s,优惠值:%s (self.discount_type.name,self.condition,self.sale)

 Activity(BaseModel):
    优惠活动
    name = models.CharField(max_length=150,1)">活动名称)
    start_time = models.DateTimeField(verbose_name=优惠策略的开始时间)
    end_time = models.DateTimeField(verbose_name=优惠策略的结束时间ly_activity
        verbose_name=商品活动
        verbose_name_plural=return self.name

 CoursePriceDiscount(BaseModel):
    课程与优惠策略的关系表
    course = models.ForeignKey(Courseactiveprices课程)
    active = models.ForeignKey(Activityactivecourses活动)
    discount = models.ForeignKey(CourseDiscountdiscountcourse优惠折扣ly_course_price_dicount课程:%s,优惠活动: %s,开始时间:%s,结束时间:%s" % (self.course.name,self.active.name,self.active.start_time,self.active.end_time)
优惠活动策略的表结构设计

2.课程列表页显示优惠类型名称

1.course/models.py

在模型类中写入discount_name 让课程列表页页面显示优惠类型名称

 Course:
    
    def activity(self):
        import datetime
        now = datetime.datetime.now()
        
         获取课程参加的活动名称
        activity_list = self.activeprices.filter(is_show=True,is_deleted=False,active__start_time__lte=now,active__end_time__gte=now)
         activity_list

     优惠类型名称
     discount_name(self):
        dis_name = ''
        a = self.activity()
        if a:
            discount_n_list = []
            for i in a:
                 获取课程的折扣类型名称
                discount_n = i.discount.discount_type.name
                discount_n_list.append(discount_n)
            dis_name = discount_n_list[0]

        return dis_name

2.course/serializers.py

序列化器加入该字段

 CourseModelSerializer:
    field = [,discount_name]
 CourseDetailModelSerializer:
    field = [,discount_name]

3.drf测试:course/courses

3.课程列表页显示真实价格

1.dev.py

USE_TZ = False  修改时区

2.course/models.py

 Course:
     real_price(self):
        price = float(self.price)  获取真实价格
        r_price = price 

        a = self.activity()  获取课程对应的活动名称
        if a:  如果课程参加了活动
            sale = a[0].discount.sale  查看活动对应的优惠公式
            condition_price = a[0].discount.condition  查看活动对应的满足优惠的价格条件
             限时免费
            if not sale.strip():
                r_price = 0

             限时折扣  *0.5
            elif *'  sale.strip():
                if price >= condition_price:
                    _,d = sale.split(')
                    r_price = price * float(d)
             限时减免  -100
            elif sale.strip().startswith(-):
                )
                    r_price = price - 满减 满100-15
             sale:
                if price >= condition_price:  只有价格满足优惠条件价格才能满减
                    l1 = sale.split(rn)
                    dis_list = []  10 50  25
                     l1:
                        a,b = i[1:].split()

                         当商品价格(400) 满足100-200-300 应该选择满300那个优惠
                         float(a):
                            dis_list.append(float(b))

                    max_dis = max(dis_list)  取到最大的那个满减优惠
                    r_price = price - max_dis  原价格-满减价格=真实价格

        return r_price

3.course/serializers.py



<!-- Course.vue -->
<div ="pay-box">
    span ="discount-type" v-if="course.discount_name">{{course.discount_name}}</span="discount-price">¥{{course.real_price}}元="original-price">原价:{{course.price}}元="buy-now">立即购买>
div>
    

2.课程详情页前端

 Detail.vue ="sale-time"p ="sale-type">{{course_data.discount_name}}p="expire">距离结束:仅剩 567 天 12小时 52分 ="second">32>="course-price">活动价="discount">¥{{course_data.real_price}}="original">¥{{course_data.price}}>

5.课程列表页显示具体结束时间

1.course/models.py

 left_time(self):
         datetime
        now = datetime.datetime.now().timestamp()  获取当前时间戳
        left_t = 0
        a = self.activity()  获取当前课程参加的活动
         如果当前课程有参加活动
            end_time = a[0].active.end_time.timestamp()  获取当前课程活动的结束时间
            left_t = end_time - now  剩余时间=结束时间-当前时间

            return left_t

2.序列化器放入left_time

course/serializers.py

Detail.vue

 html >距离结束:仅剩 {{course_data.left_time/60/60/24 | pInt}}天 {{course_data.left_time/60/60 % 24| pInt}}小时 {{course_data.left_time/60 % 60 | pInt}}分 >{{course_data.left_time % 60 | pInt}}>

在js部分需要设置一个定时器,让时间能够一直减1s

get_course_data(){ this.$axios.get(`${this.$settings.Host}/course/detail/${this.course_id}/`) .then((res)=>{ //console.log(res.data); this.course_data = res.data; this.playerOptions.sources[0].src = res.data.course_video this.playerOptions.poster = res.data.course_img 设置计时器 setInterval(()=>{ this.course_data.left_time--; },1000) }) },

补充:让页面可以显示出0x分0x秒的效果→过滤器

Detail.vue--html --> >距离结束:仅剩 {{course_data.left_time/60/60/24 | pInt}}天
{{course_data.left_time/60/60 % 24| pInt}}小时
{{course_data.left_time/60 % 60 | pInt}}分
>

 Detail.vue--js
 filters:{
      pInt(val){
        let a = parseInt(val);
        if (a < 10){
          a = `0${a}`;
        }
         a
      }
    }

2.添加购物车/查看购物车的用户认证

为视图添加IsAuthenticated用户认证

?

 cart/views.py
 AddCartView:
    
     请求头必须携带着token
    permission_classes = [IsAuthenticated,]  添加用户认证
     add:
        user_id = request.user.id  获取真实的用户id
        '''
        request = user_obj
        '''
    

drf接口: cart/add_cart 获取不到数据,因为加了IsAuthenticated认证

添加购物车时需要携带token 否则不能添加购物车

 Detail.vue 添加购物车
    methods: {

      addCart(){

        let token = localStorage.token || sessionStorage.token;

         (token){
          this.$axios.post(`${this.$settings.Host}/users/verify/`,{
              token:token,}).then((res)=>{
    this.$settings.Host}/cart/add_cart/`,{
                course_id:this.course_id,},{
               向后端提交数据需要加上header项,将token也要提交过去
              headers:{
                'Authorization':'jwt ' + token
              }
            }).then((res)=>{
                .$message.success(res.data.msg);
                console.log('>>>>>',.$store)
                this.$store.commit('add_cart',res.data.cart_length) ;
                console.log(.$store.state);
              })

            }).catch((error)=>{
             ......
            })


        } else {
          ......
              })
        }

      },

查看购物车时需要携带token 否则不能添加购物车

 Cart.vue 购物车页面
created() {
    let token = sessionStorage.token || localStorage.token;
     (token){

       查看购物车页面也要携带token 否则不能查看
         headers:{
                'Authorization':'jwt ' + token
              }
      })
      .then((res)=>{
        this.cart_data_list = res.data.cart_data_list
      })
      ..$message.error(error.response.data.msg);
      })

3.购物车商品价格的勾选/结算

1.每个课程的真实价格显示到购物车页面上

 cart/views.py

 AddCartView:
 cart_list(self,request):
       ......
        cart_data_list.append({
           ......
            real_price: course_obj.real_price(),......
        })
       ......
 cartitem.vue ="cart_column column_4">¥{{cart.real_price}}>

2.勾选/非勾选应在redis中实时存储-后端接口

 AddCartView:
     change_select(self,request):
        
         拿到课程id
        course_id = request.data.get(course_id)
        
         校验课程id合法性
        try:
            models.Course.objects.get(id=course_id)
        except:
            return Response({msg': 课程不存在,不要乱搞!'},status=status.HTTP_400_BAD_REQUEST)
        
         拿到user_id
        user_id = request.user.id
        
         去redis数据库:cart
        conn = get_redis_connection(cart redis存数据-用集合存:用户id:勾选课程id
        conn.sadd(selected_cart_%s' % user_id,course_id)
        
        ':勾选成功})   
    
        cancel_select(self,request):
        course_id = request.data.get()

        status.HTTP_400_BAD_REQUEST)

        user_id = request.user.id
        conn = get_redis_connection(')   1:{1,3}
        conn.srem(恭喜你!少花钱了,但是你真的不学习了吗!'}) 

为两个函数配置路由

 cart/urls.py
from django.urls  path,re_path
from .  views

urlpatterns = [
    path(add_cart/postaddgetcart_listpatchchange_selectputcancel_select'}))  不同的请求方法走不同函数

]

3.勾选/非勾选应该在前端页面重新计算价格

 当用户点击前面的勾选框时,会改变selected的值
近而会被watch监听到
在监听中 无论是选中还是取消选中都会触发父级标签重新计算价格的动作(this.$emit) el-checkbox ="my_el_checkbox" v-model="cart.selected"></el-checkbox>
 Cartitem.vue
watch:{

      'cart.selected':function (){
          
         添加选中
        let token = localStorage.token || sessionStorage.token;
        if (.cart.selected){
          this.$axios.patch(`${.cart.course_id,{
            headers:{
              'Authorization':'jwt ' + token
            }
          }).then((res)=>.$message.success(res.data.msg);
            this.$emit('cal_t_p')  触发cart组件计算商品总价格的方法
          })..$message.error(res.data.msg);
          })
        }
         {
            
           取消选中
          this.$axios.put(`${.$message.error(res.data.msg);
          })
        }
      },}

触发Cart组件(父组件)的计算商品总价格的方法

 Cart.vue -->
 ="cart_course_list">
     
     CartItem v-for="(value,index) in cart_data_list" :key="index" :cart="value" @cal_t_p="cal_total_price"CartItem>

 Cart.vue
methods:{
    cal_total_price(){
        
        let t_price = 0
        this.cart_data_list.forEach((v,k)=>{  v是值 k是索引
           (v.selected){
            t_price += v.real_price
          }
        })
        this.total_price = t_price

      }
}

4.购物车列表显示-后端接口

 request.user.id

        conn = get_redis_connection()

        conn.delete( user_id)
        ret = conn.hgetall(cart_%s' % user_id)   dict {b'1': b'0',b'2': b'0'}
        cart_data_list = []
        
        for cid,eid  ret.items():
                course_id = cid.decode(utf-8')  取出用户购物车里的课程id(redis中存着呢)
                expire_id = eid.decode( 取出用户购物车里的有效期id(redis中存着呢)

                course_obj = models.Course.objects.get(id=course_id)  根据课程id,通过ORM查询得到课程对象,在下面就可以通过课程对象.字段 取到对应课程的参数信息

                cart_data_list.append({
                    : course_obj.id,name: course_obj.name,1)">course_img': constants.SERVER_ADDR + course_obj.course_img.url,1)">price: course_obj.price,1)">expire_id: expire_id,1)">selected': False,1)"> 默认没有勾选
                })
         Exception:
            logger.error(获取购物车数据失败)
            后台数据库出问题了,请联系管理员status.HTTP_507_INSUFFICIENT_STORAGE)

        xxxcart_data_list: cart_data_list})
    

BUG:勾选两个课程 刷新页面 redis中仍然存着两个课程id

)
     用户刷新页面时,从redis中删除用户对应的课程id
    conn.delete( user_id)
    ret = conn.hgetall( user_id)  
    ......

?

(编辑:李大同)

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

    推荐文章
      热点阅读