Django+Vue生鲜电商

【Vue+DRF生鲜电商】17.DRF实现商品详情及热卖商品接口

2019-05-30  本文已影响11人  吾星喵

更多内容请点击我的博客

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/

BLOG_20190530_155352_25

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

BLOG_20190530_155344_89

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

BLOG_20190530_155332_59

顶部的面包屑只显示该商品的分类,定义在 src/views/productDetail/current-loc/current-loc.vue 中

            <div class="menus">
                <a href="">首页</a>
                <code>&gt;</code>
                <!--<a href="">{{curLoc.category.name}}</a>-->
                <router-link :to="{name: 'list', params:{id: curLoc.category.id}}">{{curLoc.category.name}}</router-link>
                <code>&gt;</code>
                {{curLoc.name}}
            </div>

商品详情就可以正常显示了,如果出现下面错误,需要修改代理。

Error occured while trying to proxy to:xxx

BLOG_20190530_155324_47

BLOG_20190530_155318_47

BLOG_20190530_155312_41

如果直接访问出错的图片 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服务后重启,访问呢就正常了

BLOG_20190530_155304_74

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/ 可以对商品图片进行管理

BLOG_20190530_155253_29

这可以对商品轮播图进行修改。

热卖商品接口实现

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/ 在过滤器中就可以看到“是否热销”过滤了

BLOG_20190530_155240_23

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

BLOG_20190530_155215_62

但是没有结果,因为数据库中没有勾选热销的商品,进入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= 就可以看到内容

BLOG_20190530_155204_90

数量也是数据库中改变的数量。

Vue显示热销商品

热卖商品组件为 src/views/productDetail/hotSales.vue

BLOG_20190530_155157_72
            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的商品。查看,欢迎来访。

上一篇 下一篇

猜你喜欢

热点阅读