用户浏览历史记录
用户在访问每个商品详情页面时,都要记录浏览历史记录
历史记录只需保存多个商品的sku_id即可,而且需要保持添加sku_id的顺序,所以采用redis中的列表来保存,redis的数据存储设计
'history_用户id': [sku_id列表]
在配置文件中增加浏览历史记录的redis配置
CACHES = {
...
"history": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.211.55.5:6379/3",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
}
1. 保存
后端接口设计
请求方式:POST /browse_histories/
请求参数:JSON 或 表单
参数 | 类型 | 是否必须 | 说明 |
---|---|---|---|
sku_id | int | 是 | 商品sku 编号 |
返回数据:JSON
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
sku_id | int | 是 | 商品sku 编号 |
后端实现
在users/serializes.py中实现序列化器
class AddUserBrowsingHistorySerializer(serializers.Serializer):
"""
添加用户浏览历史序列化器
"""
sku_id = serializers.IntegerField(label="商品SKU编号", min_value=1)
def validate_sku_id(self, value):
"""
检验sku_id是否存在
"""
try:
SKU.objects.get(id=value)
except SKU.DoesNotExist:
raise serializers.ValidationError('该商品不存在')
return value
def create(self, validated_data):
"""
保存
"""
user_id = self.context['request'].user.id
sku_id = validated_data['sku_id']
redis_conn = get_redis_connection("history")
pl = redis_conn.pipeline()
# 移除已经存在的本商品浏览记录
pl.lrem("history_%s" % user_id, 0, sku_id)
# 添加新的浏览记录
pl.lpush("history_%s" % user_id, sku_id)
# 只保存最多5条记录
pl.ltrim("history_%s" % user_id, 0, constants.USER_BROWSING_HISTORY_COUNTS_LIMIT-1)
pl.execute()
return validated_data
在users/views.py中编写视图
class UserBrowsingHistoryView(CreateAPIView):
"""
用户浏览历史记录
"""
serializer_class = AddUserBrowsingHistorySerializer
permission_classes = [IsAuthenticated]
前端实现
在detail.js中添加
mounted: function(){
// 添加用户浏览历史记录
this.get_sku_id();
if (this.user_id) {
axios.post(this.host+'/browse_histories/', {
sku_id: this.sku_id
}, {
headers: {
'Authorization': 'JWT ' + this.token
}
})
}
this.get_cart();
this.get_hot_goods();
this.get_comments();
},
2. 查看
后端接口设计
请求方式:GET /browse_histories/
请求参数: 无
返回数据: JSON
[
{
"id": 14,
"name": "华为 HUAWEI P10 Plus 6GB+128GB 玫瑰金 移动联通电信4G手机 双卡双待",
"price": "3788.00",
"default_image_url": "http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrRdMSAaDUtAAVslh9vkK04466364",
"comments": 1
},
{
"id": 16,
"name": "华为 HUAWEI P10 Plus 6GB+128GB 曜石黑 移动联通电信4G手机 双卡双待",
"price": "3788.00",
"default_image_url": "http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrRdPeAXNDMAAYJrpessGQ9777651",
"comments": 0
}
]
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
id | int | 是 | 商品sku 编号 |
name | str | 是 | 商品名称 |
price | decimal | 是 | 单价 |
default_image_url | str | 是 | 默认图片 |
comments | int | 是 | 评论量 |
后端实现
在users/views.py中UserBrowsingHistoryView视图补充get方法
from goods.serializers import SKUSerializer
class UserBrowsingHistoryView(mixins.CreateModelMixin, GenericAPIView):
"""
用户浏览历史记录
"""
...
def get(self, request):
"""
获取
"""
user_id = request.user.id
redis_conn = get_redis_connection("history")
history = redis_conn.lrange("history_%s" % user_id, 0, constants.USER_BROWSING_HISTORY_COUNTS_LIMIT-1)
skus = []
# 为了保持查询出的顺序与用户的浏览历史保存顺序一致
for sku_id in history:
sku = SKU.objects.get(id=sku_id)
skus.append(sku)
s = SKUSerializer(skus, many=True)
return Response(s.data)
前端实现
修改user_center_info.html
<h3 class="common_title2">最近浏览</h3>
<div class="has_view_list">
<ul class="goods_type_list clearfix">
<li v-for="sku in histories">
<a :href="sku.url"><img :src="sku.default_image_url"></a>
<h4><a :href="sku.url">{{sku.name}}</a></h4>
<div class="operate">
<span class="prize">¥{{sku.price}}</span>
<span class="unit">{{sku.comments}}评价</span>
</div>
</li>
</ul>
</div>
修改user_center_info.js
// 判断用户的登录状态
if (this.user_id && this.token) {
axios.get(this.host + '/user/', {
// 向后端传递JWT token的方法
headers: {
'Authorization': 'JWT ' + this.token
},
responseType: 'json',
})
.then(response => {
// 加载用户数据
this.user_id = response.data.id;
this.username = response.data.username;
this.mobile = response.data.mobile;
this.email = response.data.email;
this.email_active = response.data.email_active;
// 补充请求浏览历史
axios.get(this.host + '/browse_histories/', {
headers: {
'Authorization': 'JWT ' + this.token
},
responseType: 'json'
})
.then(response => {
this.histories = response.data;
for(var i=0; i<this.histories.length; i++){
this.histories[i].url = '/goods/' + this.histories[i].id + '.html';
}
})
})
.catch(error => {
if (error.response.status==401 || error.response.status==403) {
location.href = '/login.html?next=/user_center_info.html';
}
});
} else {
location.href = '/login.html?next=/user_center_info.html';
}