【Vue+DRF生鲜电商】17.DRF实现商品详情及热卖商品接口
更多内容请点击我的博客
viewsets实现商品详情页接口
添加商品详情类继承RetrieveModelMixin
在 goods/views.py 中显示商品列表的ViewSet为GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet)
,它继承了mixins.ListModelMixin
之后,是显示商品的列表页,如果要显示商品的详情,只需要再继承mixins.RetrieveModelMixin
,就可以了,代码如下:
class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
"""
显示商品列表,分页、过滤、搜索、排序
显示商品详情
"""
queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,) # 将过滤器后端添加到单个视图或视图集
filterset_class = GoodsFilter
# authentication_classes = (TokenAuthentication, ) # 只在本视图中验证Token
search_fields = ('name', 'goods_desc', 'category__name') # 搜索字段
ordering_fields = ('click_num', 'sold_num', 'shop_price') # 排序
在商品详情页有商品的轮播图,是关联的另一个模型GoodsImage(models.Model)
,商品有一个外键images
指向该模型。
class GoodsImage(models.Model):
"""
商品图片
"""
goods = models.ForeignKey(Goods, verbose_name='商品', help_text='商品', on_delete=models.CASCADE, related_name='images')
image = models.ImageField(upload_to='goods/images/', verbose_name='图片', help_text='图片')
add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
class Meta:
verbose_name_plural = verbose_name = '商品图片'
def __str__(self):
return self.goods.name
还需要序列化商品轮播图,修改 goods/serializers.py ,添加商品轮播图序列化类
from .models import Goods, GoodsCategory, GoodsImage
# 商品图片序列化
class GoodsImageSerializer(serializers.ModelSerializer):
class Meta:
model = GoodsImage
fields = ['image'] # 需要的字段只需要image
class GoodsSerializer(serializers.ModelSerializer):
category = CategorySerializer() # 自定义字段覆盖原有的字段,实例化
images = GoodsImageSerializer(many=True) # 字段名和外键名称一样,商品轮播图,需要加many=True,因为一个商品有多个图片
class Meta:
model = Goods
fields = '__all__'
访问后台 http://127.0.0.1:8000/goods/

可以看到每个商品的轮播图字段都已经显示了,整个轮播图url都能拼凑好,指定商品id,可以看到该商品的详细信息,例如 http://127.0.0.1:8000/goods/105/

Vue显示商品详情分析
显示商品详情的组件为 src/views/productDetail/productDetail.vue
created() {
this.productId = this.$route.params.productId;
var productId = this.productId;
// ....
}
从这可以获取到点击商品传递过来的商品id,然后调用getGoodsDetail
getDetails() { // 请求商品详情
getGoodsDetail(this.productId)
.then((response) => {
//console.log(response.data);
this.proDetail = response.data;
this.curShow = this.proDetail.images[0];
}).catch(function (error) {
console.log(error);
});
},
在 src/api/api.js 中,定义了获取商品详情的url
//获取商品列表
export const getGoods = params => {
return axios.get(`${local_host}/goods/`, {params: params})
};
//商品详情
export const getGoodsDetail = goodId => {
return axios.get(`${local_host}/goods/${goodId}` + '/')
};
访问某个商品详情 http://127.0.0.1:8080/#/app/home/productDetail/105

顶部的面包屑只显示该商品的分类,定义在 src/views/productDetail/current-loc/current-loc.vue 中
<div class="menus">
<a href="">首页</a>
<code>></code>
<!--<a href="">{{curLoc.category.name}}</a>-->
<router-link :to="{name: 'list', params:{id: curLoc.category.id}}">{{curLoc.category.name}}</router-link>
<code>></code>
{{curLoc.name}}
</div>
商品详情就可以正常显示了,如果出现下面错误,需要修改代理。
Error occured while trying to proxy to:xxx



如果直接访问出错的图片 http://127.0.0.1:8080/media/upload/goods_init/images/2_20170719161405_249.jpg 会提示
Error occured while trying to proxy to: 127.0.0.1:8080/media/upload/goods_init/images/2_20170719161405_249.jpg
修改方法,将Vue项目根目录中 proxy.js 进行修改,配置为本地服务器的地址
module.exports = {
// "/": "http://myserver.com:8001" //如果部署服务器,需修改为服务器的域名
"/": "http://127.0.0.1:8000"
};
关闭npm服务后重启,访问呢就正常了

Django后台轮播图一对多关系管理
修改 goods/admin.py 商品详情轮播图显示到同一页
from .models import GoodsCategory, Goods, GoodsImage
class GoodsImageInline(admin.TabularInline):
model = GoodsImage
@admin.register(Goods)
class GoodsAdmin(admin.ModelAdmin):
list_display = ['name']
inlines = [
GoodsImageInline
]
访问 http://127.0.0.1:8000/admin/goods/goods/105/change/ 可以对商品图片进行管理

这可以对商品轮播图进行修改。
热卖商品接口实现
DRF中增加is_hot过滤商品
在商品的model中定义了一个is_hot
字段,用于指定商品是否热销
class Goods(models.Model):
# 。。。
is_hot = models.BooleanField(default=False, verbose_name='是否热销', help_text='是否热销')
有了这个字段之后,要获取热销产品,只需要添加这个字段的过滤,修改 apps/goods/filters.py 的GoodsFilter(filters.FilterSet)
class GoodsFilter(filters.FilterSet):
"""
商品的过滤类
"""
name = filters.CharFilter(field_name='name', lookup_expr='contains') # 包含关系,模糊匹配
goods_desc = filters.CharFilter(field_name='name', lookup_expr='contains')
min_price = filters.NumberFilter(field_name="shop_price", lookup_expr='gte') # 自定义字段
max_price = filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
top_category = filters.NumberFilter(method='top_category_filter', field_name='category_id', lookup_expr='=') # 自定义过滤,过滤某个一级分类
def top_category_filter(self, queryset, field_name, value):
"""
自定义过滤内容
这儿是传递一个分类的id,在已有商品查询集基础上获取分类id,一级一级往上找,直到将三级类别找完
:param queryset:
:param field_name:
:param value: 需要过滤的值
:return:
"""
queryset = queryset.filter(Q(category_id=value) | Q(category__parent_category_id=value) | Q(category__parent_category__parent_category_id=value))
return queryset
class Meta:
model = Goods
fields = ['name', 'goods_desc', 'min_price', 'max_price', 'is_hot']
在fields
中添加is_hot
字段
访问 http://127.0.0.1:8000/goods/ 在过滤器中就可以看到“是否热销”过滤了

将是否热销选择“是”,此时链接跳转到 http://127.0.0.1:8000/goods/?name=&goods_desc=&min_price=&max_price=&is_hot=true&top_category=

但是没有结果,因为数据库中没有勾选热销的商品,进入Goods数据库,选择几个商品勾选
>>> from goods.models import Goods
>>> Goods.objects.filter(is_hot=True)
<QuerySet []>
# 勾选热销
>>> Goods.objects.filter(id__lte=110)
<QuerySet [<Goods: 新鲜水果甜蜜香脆单果约800克>, <Goods: 田然牛肉大黄瓜条生鲜牛肉冷冻真空黄牛>, <Goods: 酣畅家庭菲力牛排10片澳洲生鲜牛肉团购套餐>, <Goods: 日本蒜蓉粉丝扇贝270克6只装>, <Goods: 内蒙新鲜牛肉1斤清真生鲜牛肉火锅食材>, <Goods: 乌拉圭进口牛肉卷特级肥牛卷>]>
>>> Goods.objects.filter(id__lte=110).update(is_hot=True)
6
>>> Goods.objects.filter(is_hot=True)
<QuerySet [<Goods: 新鲜水果甜蜜香脆单果约800克>, <Goods: 田然牛肉大黄瓜条生鲜牛肉冷冻真空黄牛>, <Goods: 酣畅家庭菲力牛排10片澳洲生鲜牛肉团购套餐>, <Goods: 日本蒜蓉粉丝扇贝270克6只装>, <Goods: 内蒙新鲜牛肉1斤清真生鲜牛肉火锅食材>, <Goods: 乌拉圭进口牛肉卷特级肥牛卷>]>
现在刷新 http://127.0.0.1:8000/goods/?name=&goods_desc=&min_price=&max_price=&is_hot=true&top_category= 就可以看到内容

数量也是数据库中改变的数量。
Vue显示热销商品
热卖商品组件为 src/views/productDetail/hotSales.vue

getHotSales() { //请求热卖商品
getGoods({
is_hot: true
})
.then((response) => {
//console.log(response.data)
this.hotProduct = response.data.results;
}).catch(function (error) {
console.log(error);
});
}
这个也就是请求商品过滤is_hot: true
的商品。查看,欢迎来访。