购物车部分
-
购物车商品应当存储那些数据
- sku_id,count(用户购买几个),selected(是否被勾选)
- 登录用户: 允许使用服务器资源
- 存储到 redis,每条数据分两种格式存储
- Set:{sku_id_1,sku_id_2......} # 有放入集合(自带去重功能),就表示已勾选
- Hash:dict {sku_id_1:count,sku_id_2:count......}
- 未登录用户: 不允许使用服务器资源
- 存储到 浏览器cookie(存到 localStorage也可以...)
- cookie中只能存储'键值对',key-value都是必须是str类型
- response.set_cookie('cart','value','过期时间')
- 类似的数据格式:
{
sku_id_1:{'count':1,'selected':true},
sku_id_2:{'count':1,'selected':true}
}
pickle模块(比json模块高效)和base64模块(简单加密/解密)
-
pickle模块: 提供了对于 python 数据的序列化操作,可以将数据转换为 bytes 类型
-
pickle.dumps(): 将 python 数据序列化为 bytes 类型
-
pickle.loads(): 将 bytes 类型数据反序列化为 python 的数据类型( 字典, 对象等 )
-
import pickle
data = {'1': {'count': 10, 'selected': True}, '2': {'count': 20, 'selected': False}}
bytes_data = pickle.dumps(data)
print(bytes_data) # b'\x80\x03}q\x00(X\x01\x00\x00\x001q\x01}q\x02(X\x05\x00......
dict_data = pickle.loads(bytes_data)
print(dict_data) # {'1': {'count': 10, 'selected': True}, '2': {'count': 20, 'selected': False}}
- base64模块:把bytes类型数据,作进一步'加密'/'解密'处理
import base64
bytes_data = b'king'
encode_bytes_data = base64.b64encode(bytes_data)
print(encode_bytes_data) # b'a2luZw=='
decode_bytes_data = base64.b64decode(encode_bytes_data)
print(decode_bytes_data) # b'king'
- 项目应用
- 读取步骤
- 先获取用户是否操作过 cookie作为购物车
# cart_str是经过b64加密后的字符串
- cart_str = request.COOKIES.get('cart')
- 把 cart_str 转换为 bytes
- cart_str_bytes = cart_str.encode()
- cart_str_bytes 作 base64解密
- b64 = base64.b64decode(cart_str_bytes)
- 把 b64经过pickle.loads(),转换成字典
- cart_dict = pickle.loads(b64)
- 添加步骤
# cart_dict 是购物车数据
- 先将 cart_dict 经过 pickle.dumps()转换成 bytes
- cart_dict_bytes = pickle.dumps(cart_dict)
- 将 cart_dict_bytes 经过b64加密
- b64 = base64.b64encode(cart_str_bytes)
- 将b64转换为str,最后写入cookie
cookie_cart_str = b64.decode()
response.set_cookie('cart',cookie_cart_str)
- 后端编写购物车接口
# apps.carts.views
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
class CartView(APIView):
# authentication_classes = [JSONWebTokenAuthentication,]
# permission_classes = [IsAuthenticated,]
def post(self,request):
return Response({'msg':'响应成功'})
def get(self,request):
pass
def put(self,request):
pass
def delete(self,request):
pass
- 前端代码
......
// 添加购物车
add_cart: function(){
axios.post(this.host+'/carts/', {
// 把 sku_id 和 count 发送到后端
sku_id: parseInt(this.sku_id),
count: this.sku_count
}, {
headers: { // 校验
'Authorization': 'JWT ' + this.token
},
responseType: 'json',
withCredentials: true
})
.then(response => {
alert('添加购物车成功');
this.cart_total_count += response.data.count;
})
.catch(error => {
if ('non_field_errors' in error.response.data) {
alert(error.response.data.non_field_errors[0]);
} else {
alert('添加购物车失败');
}
console.log(error.response.data);
})
},
- 未登录用户的认证问题
- 不管用户是否登录,都必须实现购物车功能
- 而当用户未登录时候,前端依然在 headers 加入 'Authorization'
所以请求还没到视图views,就会被认证类 JSONWebTokenAuthentication 拦截
无法实现后续购物车的逻辑
- 解决办法一: 前端不在headers加入 'Authorization'
- 解决办法二: 后端作'延迟认证'处理(使用这个方法处理)
- 查看后端认证的APIView源码
- 先走dispatch
class APIView(View):
......
def dispatch(self, request, *args, **kwargs):
......
try:
# 走这个方法
self.initial(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
......
# 走认证,权限和节流
# 进 perform_authentication()
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
def perform_authentication(self, request):
### 看注释
"""
Perform authentication on the incoming request.
Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user
'''
当简单重写这个方法的时候, 校验会变'懒'(延迟校验),直至出现 request.user / request.auth
校验才会继续进行
'''
### setttings
......
#---------DRF配置项------------#
REST_FRAMEWORK = {
......
'DEFAULT_AUTHENTICATION_CLASSES': [
# 首选是JWT
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
],
# 这个权限类不能加,加上就验证: IsAuthenticated 会调用 request.user/auth
# 'DEFAULT_PERMISSION_CLASSES': [
# # IsAuthenticated 仅通过认证的用户
# 'rest_framework.permissions.IsAuthenticated'
# ]
}
### views
......
class CartView(APIView):
# 重写这个方法,延迟校验
def perform_authentication(self, request):
pass
def post(self,request):
return Response({'msg':'响应成功'})
def get(self,request):
pass
def put(self,request):
pass
def delete(self,request):
pass
- 测试: http://127.0.0.1:8000/carts/
- 参数: Authorization: JWT空格
- 加上 request.user 测试
def post(self,request):
# 启用校验逻辑,触发异常: "detail": "Invalid Authorization header. No credentials provided."
user = request.user
return Response({'msg':'响应成功'})
- 捕获该异常并继续执行我们的逻辑
def post(self,request):
try:
user = request.user
except:
user = None
return Response({'msg':'响应成功'})
标签:count,项目,request,self,bytes,cart,data,商城
From: https://www.cnblogs.com/qinganning/p/17043219.html