一.获取商品内容
Ss1. 获取某分类下的商品数据
class CateGoodsView(APIView):
def get(self, request):
print(request.META.get("USER"))
# cate_id = request.query_params.get("cate_id")
cate_name = request.query_params.get("cate_name")
# 获取分类信息
cate_info = Categroy.objects.filter(cate_name=cate_name).first()
if not cate_info:
return Response({
"code": 400,
"msg": "分类不存在"
})
# 通过分类获取分类下商品的信息
goods_all = cate_info.goods_set.all()[:7]
# 序列化
ser = GoodsSer(goods_all, many=True)
return Response({
"code": 200,
"msg": "商品获取成功",
"goods": ser.data
})
Ss2. 获取热门商品
class HotGoodsView(APIView):
def post(self, request):
cates = request.data.get("cate_name")
# 查询分类下的热门商品
goods_all = Goods.objects.filter(cate__cate_name__in=cates).order_by("-count").all()[:7]
# 序列化
ser = GoodsSer(goods_all, many=True)
return Response({
"code": 200,
"msg": "热门商品获取成功",
"goods": ser.data
})
Ss3. 获取商品详情
class GoodsInfoView(APIView):
def get(self, request, goods_id):
# 从数据库获取商品
goods_info = Goods.objects.filter(id=goods_id).first()
# 判断商品是否存在
if not goods_info:
return Response({
"code": 400,
"msg": "商品不存在",
})
# 走到这里,说明商品存在
# 序列化
ser = GoodsSer(instance=goods_info, many=False)
return Response({
"code": 200,
"msg": "商品详情获取OK",
"goods": ser.data
})
Ss4. 获取商品轮播图
class GoodsInfoImagesView(APIView):
def get(self, request, goods_id):
goods_info = Goods.objects.filter(id=goods_id).first()
if not goods_info:
return Response({
"code": 400,
"msg": "商品不存在"
})
goods_images = goods_info.goodsimages_set.all()
print(goods_images)
# 序列化方式二
# 手动序列化,把query_set格式的数据,转换为list或dict格式的数据,然后返回就可以了
img_all = []
for img_item in goods_images:
img_all.append({
"img_path": img_item.img,
"title": img_item.title,
})
return Response({
"code": 200,
"msg": "轮播图获取OK",
"imgs": img_all
})
二.历史浏览记录
Ss5. 获取历史浏览记录
class HistoryView(APIView):
def post(self, request, goods_id):
# 通过检测用户登录中间件给的user数据
user = request.META.get("USER")
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
print(user)
user_id = user["user_id"] # 拿到了当前用户的ID
# 判断一下商品是否存在
goods_info = Goods.objects.filter(id=goods_id).first()
if not goods_info:
return Response({
"code": 400,
"msg": "商品不存在"
})
# 把浏览记录存到数据库
r = redis.Redis(host="127.0.0.1", port=6379, password="123456")
# 分析历史记录的存储格式,使用list比较合适 [1,5,6,2,3,4]
key = "history:" + str(user_id) # 3 history:3
r.lrem(key, 0, goods_id) # 先从历史记录中移除
r.lpush(key, goods_id) # 再添加到redis数据库
r.ltrim(key, 0, 4) # 截取最近五条历史记录
return Response({
"code": 200,
"msg": "历史记录添加成功,商品名:" + goods_info.sku_name
})
def get(self, request):
user = request.META.get("USER")
if not user:
return Response({
"code": 400,
"msg": "用户未登录",
})
user_id = user["user_id"] # 拿到登录用户的ID
r = redis.Redis(host="127.0.0.1", port=6379, password="123456")
key = "history:" + str(user_id)
goods_list = r.lrange(key, 0, -1)
goods_all = []
for item in goods_list:
goods_id = item.decode()
goods_info = Goods.objects.filter(id=goods_id).first()
if not goods_info:
continue
goods_all.append(goods_info)
# goods_list_int.append(item.decode())
# goods_set = Goods.objects.filter(id__in=goods_list_int)
#
ser = GoodsSer(goods_all, many=True)
return Response({
"code": 200,
"msg": "获取历史记录成功",
"history": ser.data
})
三.添加收藏
Ss6.添加收藏的类视图
class AddLikeView(APIView):
def post(self, request, goods_id):
user = request.META.get("USER")
if not user:
return Response({
"code": 400,
"msg": "用户未登录",
})
user_id = user["user_id"] # 拿到登录用户的ID
# 检测商品是否存在
goods_info = Goods.objects.filter(id=goods_id).first()
if not goods_info:
return Response({
"code": 400,
"msg": "商品不存在"
})
r = redis.Redis(host="127.0.0.1", port=6379, password="123456")
key = "like:" + str(user_id) # like:3
# 判断一下,goods_id 是否已经在数据库
like_goods = r.smembers(key)
goods_ids = [] # 初始化一个列表,用于存放格式化之后的商品ID
for gid in like_goods:
goods_ids.append(gid.decode())
print(goods_ids)
if str(goods_id) in goods_ids:
return Response({
"code": 400,
"msg": "已收藏,不用重复收藏"
})
r.sadd(key, goods_id)
return Response({
"code": 200,
"msg": "添加收藏成功",
})
Ss7.展示收藏的类视图
class ShowLikeView(APIView):
def get(self, request):
user = request.META.get("USER")
if not user:
return Response({
"code": 400,
"msg": "用户未登录",
})
user_id = user["user_id"] # 拿到登录用户的ID
# 链接redis数据库
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
key = "like:" + str(user_id)
like_goods = r.smembers(key)
goods_ids = []
for gid in like_goods:
goods_ids.append(gid.decode())
# goods_ids 就是收藏的商品ID
# 通过goods_ids 查询所有商品信息
goods_all = Goods.objects.filter(id__in=goods_ids).all()
# 序列化
ser = GoodsSer(instance=goods_all, many=True)
return Response({
"code": 200,
"msg": "收藏商品获取成功",
"goods": ser.data
})
Ss8.删除收藏的类视图
class DeleteLikeView(APIView):
def post(self, request, goods_id):
user = request.META.get("USER")
if not user:
return Response({
"code": 400,
"msg": "用户未登录",
})
user_id = user["user_id"] # 拿到登录用户的ID
# 链接redis数据库
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
key = "like:" + str(user_id)
like_goods = r.smembers(key)
goods_ids = []
for gid in like_goods:
goods_ids.append(gid.decode())
if str(goods_id) not in goods_ids:
return Response({
"code": 400,
"msg": "没有收藏过"
})
r.srem(key, goods_id)
return Response({
"code": 200,
"msg": "删除成功"
})
四.购物车
Ss9.添加购物车的类视图
class CartView(APIView):
# 添加购物车
def post(self, request, goods_id):
user = request.META.get("USER") # 获取到中间件检测完登录,传递过来的用户信息,如果未登录,传递过来的是None
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
user_id = user["user_id"]
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
# key = "cart:" + str(user_id)
key = "cart:%s" % user_id
# 存入数据库
# 先判断商品是否存在
goods_info = Goods.objects.filter(id=goods_id).first()
if not goods_info:
return Response({
"code": 400,
"msg": "商品不存在"
})
cart = {
"id": goods_id, # 购物车id
"productID": goods_id, # 商品id
"productName": goods_info.sku_name, # 商品名称
"productImg": goods_info.img,
"price": goods_info.selling_price, # 商品价格
"num": 1, # 加购的商品数量
"maxNum": goods_info.stock, # 商品限购数量
"check": False # 是否勾选
}
# 当前商品是否已经在购物车
is_exist = r.hexists(key, goods_id)
if is_exist:
# 判断一下商品数量是否已经超出库存量
goods_count = r.hget(key, goods_id) # 当前商品加入购物车的数量,返回的是byte类型
goods_count_int = int(goods_count.decode()) # 把byte转换为int
if goods_count_int >= goods_info.stock:
# 说明超出库存量,不可以再添加了
return Response({
"code": 400,
"msg": "购物车商品已达上限"
})
# 购物车数量+1
r.hincrby(key, goods_id, 1)
cart["num"] = goods_count_int + 1
return Response({
"code": 201,
"msg": "商品已经在购物车,购物车数量+1",
"cart": cart,
})
else:
# 把商品添加到购物车
r.hset(key, goods_id, str(1))
return Response({
"code": 200,
"msg": "加入购物车成功",
"cart": cart
})
Ss10.修改购物车数量
def put(self, request, goods_id):
user = request.META.get("USER") # 获取到中间件检测完登录,传递过来的用户信息,如果未登录,传递过来的是None
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
user_id = user["user_id"] # 当前登录用户
num = request.data.get("num") # 修改后的数量
# 判断一下 商品是否在当前用户的购物车
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
key = "cart:%s" % user_id
is_exists = r.hexists(key, goods_id) # 判断某商品是否在购物车中
if not is_exists: # 不在
return Response({
"code": 400,
"msg": "商品不在购物车中"
})
# 判断一下商品是否存在
goods_info = Goods.objects.filter(id=goods_id).first()
if not goods_info:
return Response({
"code": 400,
"msg": "商品不存在"
})
# 判断一下是否超出了库存量
if int(num) > goods_info.stock:
return Response({
"code": 400,
"msg": "超出库存量"
})
# 修改数据库中的数据
r.hset(key, goods_id, num)
r.close()
# 返回
return Response({
"code": 200,
"msg": "购物车数量更新成功,当前数量%s" % num
})
Ss11.删除购物车
def delete(self, request, goods_id):
# 判断登录
user = request.META.get("USER") # 获取到中间件检测完登录,传递过来的用户信息,如果未登录,传递过来的是None
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
user_id = user["user_id"]
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
key = "cart:%s" % user_id
select_key = "cart_select:%s" % user_id
# 从购物车删除
r.hdel(key, goods_id)
# 从选中的商品中删除
r.srem(select_key, goods_id)
# 返回
return Response({
"code": 200,
"msg": "删除成功"
})
Ss12.查看购物车
class ShowCartView(APIView):
def get(self, request):
user = request.META.get("USER") # 获取到中间件检测完登录,传递过来的用户信息,如果未登录,传递过来的是None
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
user_id = user["user_id"]
# 获取到redis里面存储的商品信息
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
key = "cart:%s" % user_id
goods_list = r.hgetall(key)
goods_all = []
for (k, v) in goods_list.items():
k = k.decode() # 商品ID
v = v.decode() # 商品加购数量
goods_info = Goods.objects.filter(id=k).first()
if not goods_info: # 商品不存在,跳过该商品
continue
select_key = "cart_select:%s" % user_id
is_exists = r.sismember(select_key, k)
info = {
"id": k, # 购物车id
"productID": k, # 商品id
"productName": goods_info.sku_name, # 商品名称
"productImg": goods_info.img, # 商品图片
"price": goods_info.selling_price, # 商品价格
"num": int(v), # 加购的商品数量
"maxNum": goods_info.stock, # 商品限购数量
"check": is_exists # 是否勾选
}
goods_all.append(info)
return Response({
"code": 200,
"msg": "购物车获取成功",
"goods": goods_all
})
Ss13.购物车全选与取消全选
def post(self, request):
# 判断登录
user = request.META.get("USER") # 获取到中间件检测完登录,传递过来的用户信息,如果未登录,传递过来的是None
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
user_id = user["user_id"]
check = request.data.get("check") # 前台传过来的用户是否全选
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
key = "cart:%s" % user_id
select_key = "cart_select:%s" % user_id
if check == "check":
# 执行全选逻辑
# 获取购物车的所有商品ID
goods_ids = r.hkeys(key)
goods_ids_int = []
for id in goods_ids:
goods_ids_int.append(id.decode())
# 把商品ID全部添加到选中的集合里面
r.sadd(select_key, *goods_ids_int)
return Response({
"code": 200,
"msg": "全选成功"
})
# 走到这,就执行全不选的逻辑
r.delete(select_key)
return Response({
"code": 201,
"msg": "取消全选成功"
})
Ss14-购物车选中与不选中
class CartCheckView(APIView):
def post(self, request, goods_id):
# 判断登录
user = request.META.get("USER") # 获取到中间件检测完登录,传递过来的用户信息,如果未登录,传递过来的是None
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
user_id = user["user_id"]
# 判断商品是否存在
goods_info = Goods.objects.filter(id=goods_id).first()
if not goods_info:
return Response({
"code": 400,
"msg": "商品不存在"
})
# 判断商品是否在购物车
r = redis.Redis(host="127.0.0.1", port=6379, password="123")
key = "cart:%s" % user_id
is_exists = r.hexists(key, goods_id)
if not is_exists:
return Response({
"code": 400,
"msg": "商品不在购物车"
})
# 判断商品是否选中
select_key = "cart_select:%s" % user_id
is_check = r.sismember(select_key, goods_id)
if is_check: # 商品已经选中
# 执行不选中
r.srem(select_key, goods_id)
return Response({
"code": 201,
"msg": "取消选中成功"
})
# 程序走到这一步,说明商品未选中
# 执行选中
r.sadd(select_key, goods_id)
return Response({
"code": 200,
"msg": "选中成功"
})
五.订单
Ss15-获取 生成 创建 下单
class GoodsView(APIView):
# 获取订单列表
def get(self,request):
user = request.META.get("USER")
if not user:
return Response({
"code":400,
'msg':"用户未登录"
})
user_id = user["user_id"]
user_info = User.objects.filter(id = user_id).first()
order_list = user_info.order_set.order_by("-create_time").all() # 拿到用户下面所有的订单
print(order_list)
order_all = []
for order in order_list:
order_goods_list = order.ordergoods_set.all()
goods_all = []
for gd in order_goods_list:
goods_all.append({
"createdTime": order.create_time,
"orderID": order.order_id,
"payStatus": order.pay_status,
"productID": gd.goods.id,
"productImg":gd.goods.img,
"productName": gd.goods.sku_name,
"productNum": gd.count,
"productPrice": gd.price
})
if not goods_all:
continue
order_all.append(goods_all)
return Response({
"code":200,
"msg":"ok",
"order_list":order_all
})
# 生成订单
def post(self, request):
# 判断登录
user = request.META.get("USER") # 获取到中间件检测完登录,传递过来的用户信息,如果未登录,传递过来的是None
if not user:
return Response({
"code": 400,
"msg": "用户未登录"
})
user_id = user["user_id"]
addr_id = request.data.get("addr_id")
goods_list = request.data.get("goods_list") # [{"goods_id":1,"num":2},{"goods_id":2,"num":2}]
pay_method = request.data.get("pay_method")
# 获取收货地址并验证
addr_info = Addr.objects.filter(id=addr_id, user_id=user_id).first()
if not addr_info:
return Response({
"code": 400,
"msg": "收货地址不存在"
})
# 获取商品信息并验证
goods_buy = []
for goods in goods_list:
goods_info = Goods.objects.filter(id=goods["goods_id"]).first()
if not goods_info:
continue
if goods_info.stock < goods["num"]:
return Response({
"code": 400,
"msg": "%s 商品库存不足" % goods_info.sku_name,
})
goods_buy.append({
"id": goods["goods_id"],
"num": goods["num"],
"price": goods_info.selling_price
})
from django.db import transaction # 导入事务的类
with transaction.atomic(): # 开启事务
point = transaction.savepoint() # 添加事务的回滚点
try:
# 时间戳,时间格式 + userId + 随机数
from datetime import datetime
now_time = datetime.now().strftime("%Y%m%d%H%M%S")
order_id = now_time + str(user_id) + str(random.randint(100000,999999))
# 创建订单
order_info = Order.objects.create(
order_id=order_id,
user_id=user_id,
addr=addr_info,
total_price=0,
total_count=0,
pay_method=pay_method,
pay_status=1,
)
if not goods_buy:
transaction.savepoint_rollback(point) # 事务回滚
return Response({
"code":400,
"msg":"空订单"
})
# 创建订单商品
for item in goods_buy:
# 创建子订单
OrderGoods.objects.create(
goods_id=item["id"],
count=item["num"],
price=item["price"],
order=order_info,
)
# 修改主订单的数据
order_info.total_price += (item["price"] * item["num"])
order_info.total_count += item["num"]
# 扣除库存
g_info = Goods.objects.filter(id=item["id"]).first()
g_info.stock -= item["num"]
g_info.save()
order_info.save()
except Exception as e:
transaction.savepoint_rollback(point)
print(e)
return Response({
"code": 200,
"msg": "下单失败"
})
# 提交事务
transaction.savepoint_commit(point)
# 订单生成完成之后
from users.views import Pay
# 生成收银台的地址
p = Pay()
url = p.create_order(
order_id=order_info.order_id,
amount = str(order_info.total_price)
)
# 返回下单成功
return Response({
"code": 200,
"msg": "下单成功",
"url":url
})
六.分类
Ss16-商品分类
class CategroyView(APIView):
def get(self,request):
cate_list = Categroy.objects.all()
# 序列化
cate_all = [{ # 前面追加一个全部
"id":0,
"cate":"全部"
}]
for cate in cate_list:
cate_all.append({
"id":cate.id,
"cate_name":cate.cate_name
})
return Response({
"code":200,
"msg":"ok",
"cate_list":cate_all
})
路由展示
from django.urls import path
from goods import views
urlpatterns = [
path("index/cate/goods/", views.CateGoodsView.as_view()), # 获取分类下商品
path("index/hot/goods/", views.HotGoodsView.as_view()), # 获取热门商品
path("info/<int:goods_id>/", views.GoodsInfoView.as_view()), # 获取商品详情
path("info/images/<int:goods_id>/", views.GoodsInfoImagesView.as_view()), # 获取商品的轮播图
path("history/<int:goods_id>/", views.HistoryView.as_view()), # 浏览历史记录
path("history/", views.HistoryView.as_view()), # 查看浏览历史记录
path("add/like/<int:goods_id>/", views.AddLikeView.as_view()), # 添加收藏
path("show/like/", views.ShowLikeView.as_view()), # 查看收藏
path("delete/like/<int:goods_id>/", views.DeleteLikeView.as_view()), # 删除收藏
path("cart/<int:goods_id>/", views.CartView.as_view()), # 购物车的增删改
path("cart/check/<int:goods_id>/", views.CartCheckView.as_view()), # 购物车的选中与不选中
path("cart/", views.ShowCartView.as_view()), # 查看购物车、选中购物车
path("order/", views.GoodsView.as_view()), # 订单
path("groy/",views.CategroyView.as_view()) # 商品分类
]