正文共: 8098字 5图 预计阅读时间: 21分钟
https://github.com/EthanYan6/E-commerce-sites.git
结合代码查看笔记,效果更佳。笔记只是记录重点或者难点。
It is our attitude at the beginning of a difficult task which, more than anything else, will affect its successful outcome.
我们在开始做一件富有挑战性的任务时,对于成功的影响,没有什么比我们的态度更为关键的了。
小闫语录:
在大一的时候,英语老师曾经送给我们一句话『Attitude is everything.』态度决定一切。其实一件事成功与否,在这份工作上是否有建树,从一开始就决定了,那便是我们对其的态度。客观的困难不足以阻挡前进的脚步,畏惧的态度才是失败的根本原因,其他的事情就算是直接原因,那也只是『压死骆驼身上的最后一根稻草』。有着必胜的决心,不畏难的坚定,端正的态度,前方路上的困难都将是小的磕磕绊绊,你的成功从开始的这一刻便已注定,加油!
1.前端服务器live-server开启(在静态文件目录下执行)
live-server
2.开启celery任务(在celery_task上一级目录终端进行输入)
celery -A celery_task.main worker -l info
3.开启定时任务
# 添加定时任务到系统中
python manage.py crontab add
# 显示已经激活的定时任务
python manage.py crontab show
# 移除定时任务
python manage.py crontab remove
4.开启tracker服务器
docker container start tracker
5.开启storage服务器
docker container start storage
6.开启elasticsearch服务器
docker container start elasticsearch
7.进入redis查看
# 进入redis
redis-cli
# 选择数据库
select <数据库序号>
8.进入mysql数据库
mysql -h<主机地址> -P<端口号> -u<用户名> -p<密码>
API: POST /cart/
参数:
通过请求头传递jwt token
{
"sku_id":"添加商品id",
"count":"数量",
"selected":"勾选状态", # 可以不传,默认是勾选状态
}
响应:
{
"sku_id":"添加商品id",
"count":"数量",
"selected":"勾选状态"
}
1.获取参数并进行校验(参数完整,sku_id商品是否存在,商品库存是否足够[可有可无,添加购物车可要可不要,下单时必须有])。
2.获取校验之后的数据。
3.获取user。
4.保存用户的购物车记录。
4.1如果用户已经登录,在redis中保存用户的购物车记录。
4.1.1获取redis链接。
hash:在redis hash中存储用户购物车添加的商品id和数量count。
如果购物车已经添加过该商品,数量需要进行累加,如果未添加,直接添加一个新元素。
hincrby
hincrby <key> <field> <increment>
给redis hash中指定field属性的值累加increment,如果field属性不存在,直接添加一个新的属性和值。
set: 在redis set中存储用户购物车勾选的商品id
集合中的元素是唯一的
sadd
sadd <key> <member> ...
向redis set中添加元素,集合中元素是唯一的。
查看redis中是否存在。
# hash中查看所有的域field和他的值value
hgetall xxx
# set中获取key域集合的所有元素
smembers <key>
4.2如果用户未登录,在cookie中保存用户的购物车记录。
4.2.1获取原始cookie的购物车数据。
4.2.2解析cookie中购物车数据。
cart_dict = pickle.loads(base64.b64decode(cookie_cart))
4.2.3如果购物车已经添加过该商品,数量需要进行累加。
通过看商品的id是不是在购物车数据字典中,可以得知是否添加过。
4.2.3如果购物车没有添加过该商品,直接添加一个新元素。
5.返回应答,购物车记录添加成功。
5.1设置cookie中购物车数据
cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
如过出现认证未通过,可以重写父类APIView中的perform_authentication方法,直接pass跳过认证。我们在获取用户的时候使用request.user也会触发认证机制,我们可以手动对错误进行捕获而不让其报错停止。如果进行访问的时候没有传递jwt用户,是不会进行jwt验证的,会将其作为匿名用户处理。
API: GET /cart/
参数:
通过请求头传递jwt token
响应:
[
{
"id":"商品id",
"name":"商品名称",
"price":"商品价格",
"default_image_url":"默认图片",
"count":"数量",
"selected":"勾选状态"
},
...
]
1.获取用户的购物车记录
1.1如果用户已登录,从redis中获取用户的购物车记录。
1.1.1获取redis链接
redis_conn = get_redis_connection('cart')
1.1.2从redis hash中获取用户购物车中添加的商品id和对应的数量count
hgetall
hgetall <key>
获取redis hash中所有的属性和值
1.1.3从redis set中获取用户购物车中勾选的商品id
smembers
smembers <key>
获取redis set中所有的元素
1.2如果用户未登录,从cookie中获取用户的购物车记录。
1.2.1获取cookie中购物车的数据。如果没有数据是None。
1.2.2解析cookie中购物车数据
cart_dict = pickle.loads(base64.b64decode(cookie_cart))
2.根据用户购物车中商品id获取对应商品的数据。
2.1给sku对象增加属性count和selected,分别保存该商品在购物车中添加数据和勾选状态。
3.将购物车商品数据序列化并返回。
3.1添加购物车商品序列化器类。
3.2将数据序列化并返回。
API: PUT /cart/
参数:
通过请求头传递jwt token
{
"sku_id":"商品id",
"count":"修改数量",
"selected":"修改勾选状态"
}
响应:
{
"sku_id":"商品id",
"count":"修改数量",
"selected":"修改勾选状态"
}
1.获取参数并进行校验(参数完整性,sku_id商品是否存在,商品的库存)。
1.1获取校验之后的数据。
1.2获取user。
调用request.user会触发DRF框架认证过程。
2.修改用户的购物车记录。
2.1如果用户已经登录,修改redis中对应的购物车记录。
2.1.1获取redis链接。
2.1.2修改redis hash中商品id对应数量count。
hset
hset <key> <field> <value>
将redis hash中指定的field属性值设置为value。
2.1.3修改redis set中勾选的商品id。
2.1.3.1勾选,那么添加新元素。
sadd
sadd <key> <member> ...
向redis set中添加元素,集合中元素是唯一的。
2.1.3.2取消勾选,将其移除。
srem
移除
srem <key> <members> ...
从redis set中移除指定的元素,有则移除,无则忽略。
2.1如果用户没有登录,修改cookie中对应的购物车记录。
2.1.1获取cookie中的购物车数据。
2.1.2如果购物车没有数据。
2.1.3如果购物车中有数据,解析cookie中的购物车数据。
cart_dict = pickle.loads(base64.b64decode(cookie_cart))
如果获取的字典为空,表示购物车无数据。
2.1.4修改购物车数据。
3.返回应答,购物车记录修改成功。
3.1设置cookie中购物车数据。
cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
3.2返回应答,购物车记录修改成功。
1.购物车记录增加
hincrby sadd
2.购物车记录获取
hgetall smembers
3.购物车记录修改
hset sadd srem
对于上面的三个接口,都需要考虑用户是登录还是未登录。
让视图跳过DRF框架认证过程。
API: DELETE /cart/
参数:
通过请求头传递jwt token
{
"sku_id":"商品id"
}
响应:
{
"sku_id":"商品id"
}
1.获取商品skuid并进行校验(skuid必传,sku_id对应商品是否存在)。
1.1获取校验之后的数据。
1.2获取用户,防止触发DRF框架的认证机制,对错误进行捕获。
2.删除用户的购物车记录。
2.1如果用户已登录,删除redis中对应的购物车记录。
2.1.1获取redis链接
2.1.2从redis hash中删除对应商品的id和数量count
hdel
hdel <key> <field> ...
删除redis hash中指定的field属性和值。
2.1.3从redis set中删除对应商品的id
srem
移除
srem <key> <members> ...
从redis set中移除指定的元素,有则移除,无则忽略。
2.2如果用户未登录,删除cookie中对应的购物车记录。
2.2.1获取cookie中的购物车记录。
2.2.2如果无数据,直接返回204;如果有数据需要解析cookie中购物车数据。
cart_dict = pickle.loads(base64.b64decode(cookie_cart))
2.2.3删除对应的购物车记录。
2.2.4重新设置cookie购物车数据。
cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
3.返回应答,购物车记录删除成功。
API: PUT /cart/selection/
参数:
通过请求头传递jwt token
{
"selected": "勾选状态", # True:全选, False:取消全选
}
响应:
{
"message": "OK"
}
1.获取参数selected并进行校验(selected必传)。
1.1获取校验之后的selected。
1.2获取用户。
2.设置用户购物车记录勾选状态。
2.1如果用户已登录,设置redis中用户购物车记录勾选状态。
2.1.1获取redis链接。
2.1.2从redis hash中获取用户购物车中所有商品的id。
2.1.3全选:将用户购物车所有商品的id添加到redis set中。
2.1.4全不选:将用户购物车所有商品的id从redis set中移除。
2.2如果用户未登录,设置cookie中用户购物车记录勾选状态。
2.2.1获取cookie的购物车记录。
2.2.2解析cookie中的购物车数据
cart_dict = pickle.loads(base64.b64decode(cookie_cart))
2.2.3设置cookie购物车记录勾选状态。
3.返回应答,设置成功。
3.1设置cookie中的购物车数据
cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
用户登录时,将cookie中的购物车数据合并到登录用户redis购物车记录中。
只需将购物车记录合并封装成函数,然后在登录过程进行调用。
登录过程调用合并购物车函数:
1.普通账户密码登录。
2.QQ登录。
# 假如id为2的用户登录之前
# cookie中的购物车记录如下
{
11:{
'count': 1,
'selected': False
},
15: {
'count': 2,
'selected': True
}
}
cart_dict = {
11: 1,
15: 2
}
cart_selected_add = [15]
cart_selecte_remove = [11]
# redis中的购物车记录如下
cart_2: {
'11': '2',
'16': '3',
'9': '1'
}
cart_selected_2:('11', '9')
如果id为2的用户进行了登录,需要将cookie中的购物车数据合并到用户redis购物车记录中,如何进行合并?
答:当进行购物车记录合并时,如果cookie中的购物车数据和redis中的购物车数据发生了冲突,直接以cookie中的购物车数据为准,用cookie中的购物车数据去覆盖redis中对应的数据。如果没有冲突,都进行保留。
cart_2: {
'11': '1',
'15': '2',
'16': '3',
'9': '1'
}
cart_selected_2('15','9')
11的数据因为发生了冲突,覆盖后,取消了勾选。
假如id为2的用户登录之前,cookie中的购物车记录如下:
{
1: {
'count': 3,
'selected': False
},
3: {
'count': 2,
'selected': True
},
5: {
'count': 2,
'selected': True
}
}
redis中的购物车记录如下:
cart_2: {
'1': '2',
'5': '1',
'7': '3'
}
cart_selected_2: ('1', '7')
合并之后的数据如下:
cart_2: {
'1': '3',
'3': '2',
'5': '2',
'7': '3'
}
cart_selected_2: ('3', '5', '7')
将cookie中的购物车记录合并到登录用户的redis记录中。
1.获取cookie中购物车记录。
2.如果cookie购物车中无数据,就不需要合并了。
3.如果cookie购物车中有数据,需要解析cookie中的购物车数据。
cart_dict = pickle.loads(base64.b64decode(cookie_cart))
4.如果解析出来的字典为空,表明cookie购物车中无数据,也不需要合并。
5.将cookie中购物车记录合并到登录用户的redis记录中
6.组织一个字典,存储cookie购物车记录中添加的商品id和对应数量count。此字典中的数据在进行购物车记录合并时需要设置到redis hash中。
7.组织一个列表,存储cookie购物车记录中被勾选的商品的id。此列表中的商品的id在进行购物车记录合并时,需要添加到redis set中。
8.组织一个列表,存储cookie购物车记录中未被勾选商品的id。此列表中商品id在进行购物车记录合并时需要从redis set中移除。
9.遍历解析之后的字典,将勾选与未勾选的数据分别加入对应的列表中。
10.合并:将组织的字典中key和value作为属性和值设置到redis对应的hash元素中。
11.将需要添加到redis的列表中商品id添加到redis对应的set元素中。
12.将需要从redis中移除的列表中商品的id从redis对应的set元素中移除。
13.删除cookie中购物车数据。
response.delete_cookie('cart')
hmset
hmset <key> <field> <value> [<field> <value>....]
同时将多个field属性和值设置到哈希表key中。此命令会覆盖以存在的属性。
rest_framework_jwt提供的obtain_jwt_token视图,
实际从rest_framework_jwt.views.ObtainJSONWebToken类视图而来,
我们可以重写此类视图里的post方法来添加合并逻辑。
from rest_framework_jwt.views import ObtainJSONWebToken
class UserAuthorizeView(ObtainJSONWebToken):
"""
用户认证
"""
def post(self, request, *args, **kwargs):
# 调用父类的方法,获取drf jwt扩展默认的认证用户处理结果
response = super().post(request, *args, **kwargs)
# 仿照drf jwt扩展对于用户登录的认证方式,判断用户是否认证登录成功
# 如果用户登录认证成功,则合并购物车
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
user = serializer.validated_data.get('user')
response = merge_cart_cookie_to_redis(request, user, response)
return response
修改路径users/urls.py
urlpatterns = [
...
# url(r'^authorizations/$', obtain_jwt_token),
url(r'^authorizations/$', views.UserAuthorizeView.as_view()),
...
]
修改oauth/serializers.py中的序列化器
class OAuthQQUserSerializer(serializers.ModelSerializer):
...
def create(self, validated_data):
...
# 向视图对象中补充user对象属性,以便在视图中使用user
self.context['view'].user = user
return user
修改oauth/views.py中的视图
class OAuthQQUserView(CreateAPIView):
"""
获取QQ用户对应的美多商城用户
"""
serializer_class = OAuthQQUserSerializer
def get(self, request):
...
else:
reponse = Response({
'token': token,
'username': user.username,
'user_id': user.id
})
# 合并购物车
response = merge_cart_cookie_to_redis(request, user, response)
return response
def post(self, request, *args, **kwargs):
response = super().post(request, *args, **kwargs)
# 合并购物车
response = merge_cart_cookie_to_redis(request, self.user, response)
return response
优质文章推荐: