购物车
购物车表创建
关联用户、关联商品、购买的数量
class Cart(models.Model):
"""
购物车模型
"""
user = models.ForeignKey('users.User', on_delete=models.CASCADE)
goods = models.ForeignKey('goods.Goods', on_delete=models.CASCADE)
goods_num = models.IntegerField(default=1)
class Meta:
db_table = 'cart'
def __str__(self):
return '购买了{}个{}'.format(self.goods_num, self.goods.name)
购物车的添加
需要进入到商品详情页
点击加入购物车(判断用户是否登录、用户登录的话,进行添加,否则跳转到登录页面)
// 加入购物车
addCart() {
// 需要判断是否登录
if(this.token) {
// 继续添加
// 实例化表单
let form_data = new FormData()
// 添加数据
form_data.append('token', this.token)
form_data.append('goods_id', this.goods_id)
form_data.append('goods_num', this.goods_num)
// 发送请求
this.axios({
url: '/cart/add_cart/',
method: 'post',
data: form_data
}).then(res => {
console.log(res.data)
})
}else{
// 跳转到登录页面
this.$router.push({
name: 'Login',
query: {
redirect: this.$route.fullPath
}
})
}
},
添加的接口
class AddCart(APIView):
def post(self, request):
token = request.data.get('token')
goods_id = request.data.get('goods_id')
goods_num = request.data.get('goods_num') # 网页接收到的数据是字符串,需要进行整型转换
# 解析token
user_info = check_token(token)
# 判断token是否失效
if user_info:
# 获取用户id
user_id = user_info.get('user_id')
# 获取当前用户的某个商品的对象,用来判断商品是否已经添加购物车之中
cart_obj = Cart.objects.filter(user_id=user_id, goods_id=goods_id).first()
# 判断商品是否已添加,如果已添加,修改数量
if cart_obj:
cart_obj.goods_num += int(goods_num)
cart_obj.save()
return Response({'msg': '数量添加成功', 'code': 200})
# 否则的话,创建新的购物车
else:
Cart.objects.create(user_id=user_id, goods_id=goods_id, goods_num=goods_num)
return Response({'msg': '添加成功', 'code': 200})
else:
return Response({'msg': '请重新登录', 'code': 400})
需要判断用户是否登录
再判断当前用户下是否已经购买过此商品
购买过的话,进行改变数量
否则的话,添加新的购物车
展示购物车
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXIwhEXN-1611814538006)(images\image-20201225140621933.png)]
判断用户是否登录
用户登录时,携带用户id进行获取当前用户下的购物车信息
没有登录时,跳转到登录页面
class CartView(APIView):
"""
购物车展示
"""
def get(self, request):
user_id = request.query_params.get('user_id')
# 通过用户id去购物车中过滤当前用户下的所有的商品信息
cart_list = Cart.objects.filter(user_id=user_id)
# 进行序列
cart_serializer = ShowCartModelSerializer(cart_list, many=True)
# 返回数据
return Response(cart_serializer.data)
vue页面获取数据,并展示
<template>
<div>
<!-- 在这里引入头部信息 -->
<my-header></my-header>
<div class="search_bar clearfix">
<a href="index.html" class="logo fl"><img src="/static/images/logo.png"></a>
<div class="sub_page_name fl"> 购物车</div>
<div class="search_con fr">
<input type="text" class="input_text fl" name="" placeholder="搜索商品">
<input type="button" class="input_btn fr" name="" value="搜索">
</div>
</div>
<div class="total_count">全部商品<em>2</em>件</div>
<ul class="cart_list_th clearfix">
<li class="col01">商品名称</li>
<li class="col02">商品单位</li>
<li class="col03">商品价格</li>
<li class="col04">数量</li>
<li class="col05">小计</li>
<li class="col06">操作</li>
</ul>
<!-- 购物车展示 -->
<ul class="cart_list_td clearfix" v-for="cart in cart_list" :key="cart.id">
<li class="col01"><input type="checkbox" name="" checked></li>
<li class="col02"><img :src="base_url + cart.goods.image"></li>
<li class="col03">{{cart.goods.name}}<br><em>{{cart.goods.price}}元/kg</em></li>
<li class="col04">kg</li>
<li class="col05">{{cart.goods.price}}元</li>
<li class="col06">
<div class="num_add">
<a href="javascript:;" class="add fl">+</a>
<input type="text" class="num_show fl" v-model="cart.goods_num">
<a href="javascript:;" class="minus fl">-</a>
</div>
</li>
<li class="col07">{{(cart.goods.price * cart.goods_num).toFixed(2)}}元</li>
<li class="col08"><a href="javascript:;">删除</a></li>
</ul>
<ul class="settlements">
<li class="col01"><input type="checkbox" name="" checked=""></li>
<li class="col02">全选</li>
<li class="col03">合计(不含运费):<span>¥</span><em>42.60</em><br>共计<b>2</b>件商品</li>
<li class="col04"><a href="place_order.html">去结算</a></li>
</ul>
<!-- 引用组件 -->
<my-fooder></my-fooder>
</div>
</template>
<script>
// 导入组件
import Fooder from './Fooder'
import Header from './Header'
export default {
// 注册组件
components: {
'my-fooder': Fooder,
'my-header': Header
},
data() {
return {
user_id: sessionStorage.getItem('user_id'),
cart_list: [],
base_url: 'http://127.0.0.1:8000'
}
},
methods: {
// 获取购物车信息
getCart() {
this.axios({
url: '/cart/cart/?user_id=' + this.user_id
}).then(res => {
console.log(res.data)
this.cart_list = res.data
})
}
},
created() {
this.getCart()
}
}
</script>
路由守卫
当进入某一个路由地址,进行判断,判断用户是否登录,sessionStoage里面获取user_id
import Vue from 'vue'
import Router from 'vue-router'
import Cart from '@/components/Cart'
Vue.use(Router)
const router = new Router({
mode: 'history',
routes: [
{
path: '/cart',
name: 'Cart',
component: Cart,
meta: {
// 用来判断当前进入用户是否已登录,如果未登录的话,进行登录
is_login: true
}
}
]
})
router.beforeEach((to, from, next) => {
// 先进行判断,判断要进入的路由是否需要进行登录
if(to.meta.is_login) {
// 需要登录,进行登录判断
let user_id = sessionStorage.getItem('user_id')
if(user_id) {
next()
}else{
next({
name: 'Login',
query: {
redirect: to.fullPath
}
})
}
}else{
// 不需要登录 时要做的事情
next()
}
})
export default router
购物车
加减数量接口
class AddNumView(APIView):
"""
购物车加数量
"""
def post(self, request):
# 获取前端提交的购物车id
cart_id = request.data.get('cart_id')
# 通过购物车id,获取购物车的对象
try:
cart_obj = Cart.objects.get(pk=cart_id)
except Cart.DoesNotExist:
# 返回数据有误
return Response({'msg': '数据有误', 'code': 400})
# 对象存在 进行加数量
else:
cart_obj.goods_num += 1
cart_obj.save()
return Response({'msg': '添加成功', 'code': 200})
class MinusNumView(APIView):
"""
购物车加数量
"""
def post(self, request):
# 获取前端提交的购物车id
cart_id = request.data.get('cart_id')
# 通过购物车id,获取购物车的对象
try:
cart_obj = Cart.objects.get(pk=cart_id)
except Cart.DoesNotExist:
# 返回数据有误
return Response({'msg': '数据有误', 'code': 400})
# 对象存在 进行加数量
else:
if cart_obj.goods_num > 1:
cart_obj.goods_num -= 1
cart_obj.save()
return Response({'msg': '减成功', 'code': 200})
else:
return Response({'msg': '数量不足', 'code': 400})
加减数量页面方法
<script>
// 导入组件
import Fooder from './Fooder'
import Header from './Header'
export default {
data() {
return {
}
},
methods: {
// 购物车减数量
minusNum(cart_id) {
// 实例化
let form_data = new FormData()
// 添加数据
form_data.append('cart_id', cart_id)
// 发送请求
this.axios({
url: '/cart/minus_num/',
method: 'post',
data: form_data
}).then(res => {
console.log(res.data)
if(res.data.code == 200) {
// 重新调用获取购物车的方法
this.getCart()
}
})
},
// 购物车加数量
addNum(cart_id) {
// 实例化
let form_data = new FormData()
// 添加数据
form_data.append('cart_id', cart_id)
// 发送请求
this.axios({
url: '/cart/add_num/',
method: 'post',
data: form_data
}).then(res => {
console.log(res.data)
if(res.data.code == 200) {
// 重新调用获取购物车的方法
this.getCart()
}
})
},
// 获取购物车信息
getCart() {
this.axios({
url: '/cart/cart/?user_id=' + this.user_id
}).then(res => {
console.log(res.data)
this.cart_list = res.data
})
}
},
created() {
this.getCart()
}
}
</script>
全选与多选并计算金额
<template>
<div>
<!-- 在这里引入头部信息 -->
<my-header></my-header>
<div class="search_bar clearfix">
<a href="index.html" class="logo fl"><img src="/static/images/logo.png"></a>
<div class="sub_page_name fl"> 购物车</div>
<div class="search_con fr">
<input type="text" class="input_text fl" name="" placeholder="搜索商品">
<input type="button" class="input_btn fr" name="" value="搜索">
</div>
</div>
<div class="total_count">全部商品<em>2</em>件</div>
<ul class="cart_list_th clearfix">
<li class="col01">商品名称</li>
<li class="col02">商品单位</li>
<li class="col03">商品价格</li>
<li class="col04">数量</li>
<li class="col05">小计</li>
<li class="col06">操作</li>
</ul>
<!-- 购物车展示 -->
<ul class="cart_list_td clearfix" v-for="cart in cart_list" :key="cart.id">
<li class="col01"><input type="checkbox" name="" @click="multipleChoice(cart.id, cart.goods.price, cart.goods_num)" v-model="checkBox_list" :value="cart.id"></li>
<li class="col02"><img :src="base_url + cart.goods.image"></li>
<li class="col03">{{cart.goods.name}}<br><em>{{cart.goods.price}}元/kg</em></li>
<li class="col04">kg</li>
<li class="col05">{{cart.goods.price}}元</li>
<li class="col06">
<div class="num_add">
<a href="javascript:;" class="add fl" @click="addNum(cart.id)">+</a>
<input type="text" class="num_show fl" v-model="cart.goods_num">
<a href="javascript:;" class="minus fl" @click="minusNum(cart.id)">-</a>
</div>
</li>
<li class="col07">{{(cart.goods.price * cart.goods_num).toFixed(2)}}元</li>
<li class="col08"><a href="javascript:;" @click="delCart(cart.id)">删除</a></li>
</ul>
<ul class="settlements">
<li class="col01"><input type="checkbox" name="" v-model="checked" @click="selectAll"></li>
<li class="col02">全选</li>
<li class="col03">合计(不含运费):<span>¥</span><em>{{(total).toFixed(2)}}</em><br>共计<b>{{checkBox_list.length}}</b>件商品</li>
<li class="col04"><a href="place_order.html">去结算</a></li>
</ul>
<!-- 引用组件 -->
<my-fooder></my-fooder>
</div>
</template>
<script>
// 导入组件
import Fooder from './Fooder'
import Header from './Header'
export default {
// 注册组件
components: {
'my-fooder': Fooder,
'my-header': Header
},
data() {
return {
user_id: sessionStorage.getItem('user_id'),
cart_list: [],
base_url: 'http://127.0.0.1:8000',
checkBox_list: [],
checked: false,
total: 0
}
},
methods: {
// 删除购物车
delCart(cart_id) {
let form_data = new FormData()
// 添加数据
form_data.append('cart_id', cart_id)
// 发送请求
this.axios({
url: '/cart/del_cart/',
method: 'delete',
data: form_data
}).then(res => {
console.log(res.data)
if(res.data.code == 200) {
this.getCart()
}
})
},
// 计算总价
sumTotal() {
for(let i in this.cart_list) {
this.total += this.cart_list[i].goods.price * this.cart_list[i].goods_num
}
return this.total
},
// 全选
selectAll() {
// 判断全选的状态
if(this.checked) {
// 为true时,全不选
this.checkBox_list = []
this.total = 0
}else{
this.total = 0
this.checkBox_list = []
this.cart_list.forEach(item => {
this.checkBox_list.push(item.id)
})
// 商品全选时,计算总价
this.sumTotal()
console.log(this.checkBox_list)
}
},
// 多选
multipleChoice(cart_id, goods_price, goods_num) {
// 判断购物车id在不在列表中
// includes(element) 判断元素在不在列表中
if(this.checkBox_list.includes(cart_id)){
// 如果在里面的话,进行切除 splice(开始位置, 切除几个元素) indexOf(element) 获取元素下标
this.checkBox_list.splice(this.checkBox_list.indexOf(cart_id), 1)
// 取消选中,减去对应的金额
this.total -= goods_price * goods_num
}else{
this.checkBox_list.push(cart_id)
this.total += goods_price * goods_num
}
if(this.checkBox_list.length == this.cart_list.length) {
this.checked = true
}else{
this.checked = false
}
console.log(this.checkBox_list)
},
// 购物车减数量
minusNum(cart_id) {
// 实例化
let form_data = new FormData()
// 添加数据
form_data.append('cart_id', cart_id)
// 发送请求
this.axios({
url: '/cart/minus_num/',
method: 'post',
data: form_data
}).then(res => {
console.log(res.data)
if(res.data.code == 200) {
// 重新调用获取购物车的方法
this.getCart()
}
})
},
// 购物车加数量
addNum(cart_id) {
// 实例化
let form_data = new FormData()
// 添加数据
form_data.append('cart_id', cart_id)
// 发送请求
this.axios({
url: '/cart/add_num/',
method: 'post',
data: form_data
}).then(res => {
console.log(res.data)
if(res.data.code == 200) {
// 重新调用获取购物车的方法
this.getCart()
}
})
},
// 获取购物车信息
getCart() {
this.axios({
url: '/cart/cart/?user_id=' + this.user_id
}).then(res => {
console.log(res.data)
this.cart_list = res.data
})
}
},
created() {
this.getCart()
}
}
</script>
删除购物车的接口
class DelCartView(APIView):
"""
删除购物车
"""
def delete(self, request):
cart_id = request.data.get('cart_id')
# 通过购物车id,查找购物车对象
cart_obj = Cart.objects.filter(pk=cart_id).delete()
# 返回
return Response({'msg': '删除成功', 'code': 200})
购物车组件
<template>
<div>
<div class="guest_cart fr">
<a href="#" class="cart_name fl">我的购物车</a>
<div class="goods_count fl" id="show_count">{{cart_num}}</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
cart_num: {
default: 0
}
}
}
</script>
首页
<template>
<div>
<div class="search_bar clearfix">
<!-- 购物车组件 -->
<my-cart :cart_num="cart_num"></my-cart>
</div>
</div>
</template>
<script>
import MyCart from './MyCart'
export default {
// 注册组件
components: {
'my-cart': MyCart
},
data() {
return {
user_id: sessionStorage.getItem('user_id'),
cart_num: 0
}
},
methods: {
// 购物车展示数量
getCart() {
if(this.user_id) {
this.axios({
url: '/cart/cart_count/?user_id=' + this.user_id
}).then(res => {
console.log(res.data)
if(res.data.code == 200) {
this.cart_num = res.data.cart_num
}
})
}
},
},
created() {
// 页面加载时,获取购物车数据
this.getCart()
}
}
</script>