【Vue+DRF生鲜电商】31.首页商品按分类显示推荐功能

专题:Vue+Django REST framework前后端分离生鲜电商

Vue+Django REST framework 打造前后端分离的生鲜电商项目(慕课网视频)。
Github地址:https://github.com/xyliurui/DjangoOnlineFreshSupermarket
Django版本:2.2、djangorestframework:3.9.2。
前端Vue模板可以直接联系我拿。

更多内容请点击 我的博客 查看,欢迎来访。

首页商品分类显示功能

这里面有多个一对多的关系:

  • 一级分类—品牌图片Brand
  • 一级分类—二级分类
  • 一级分类—商品

在 apps/goods/models.py 中GoodsCategoryBrand添加分类的外键关联名

class GoodsCategoryBrand(models.Model):
    """
    品牌
    """
    category = models.ForeignKey(GoodsCategory, null=True, blank=True, on_delete=models.CASCADE, verbose_name='商品类别', help_text='商品类别', related_name='brands')
    # ......

Goods中也添加一个分类关联名

class Goods(models.Model):
    """
    商品
    """
    category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, verbose_name='商品类别', help_text='商品类别', related_name='goods')
    # ......

方便之后从分类中通过关联名称直接取到品牌图片和商品。

IndexCategoryGoodsSerializer序列化首页分类商品

在 apps/goods/serializers.py 新建一个 apps/goods/serializers.py类,用于序列化一级分类,以及该分类下的品牌图片,二级分类,和子分类下的所有商品。

from .models import Goods, GoodsCategory, GoodsImage, Banner, GoodsCategoryBrand


# 品牌图片
class BrandsSerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategoryBrand
        fields = "__all__"


# 首页分类商品序列化
class IndexCategoryGoodsSerializer(serializers.ModelSerializer):
    brands = BrandsSerializer(many=True)  # 分类下的品牌图片
    # goods = GoodsSerializer(many=True)  # 不能这样用,因为现在需要的是一级分类,而大多数商品是放在三级分类中的,所以很多商品是取不到的,所以到自己查询一级分类子类别下的所有商品
    goods = serializers.SerializerMethodField()
    sub_category = CategorySerializer2(many=True)  # 序列化二级分类

    def get_goods(self, obj):
        # 查询每级分类下的所有商品
        all_goods = Goods.objects.filter(Q(category_id=obj.id) | Q(category__parent_category_id=obj.id) | Q(category__parent_category__parent_category_id=obj.id))
        # 将查询的商品集进行序列化
        goods_serializer = GoodsSerializer(all_goods, many=True)
        # 返回json对象
        return goods_serializer.data

    class Meta:
        model = GoodsCategory
        fields = '__all__'

IndexCategoryGoodsViewSet首页分类及商品显示

apps/goods/views.py 添加IndexCategoryGoodsViewSet类,用于首页显示

from .serializers import GoodsSerializer, CategorySerializer, ParentCategorySerializer, BannerSerializer, IndexCategoryGoodsSerializer

class IndexCategoryGoodsViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    list:
        首页分类、商品数据
    """
    queryset = GoodsCategory.objects.filter(category_type=1)
    serializer_class = IndexCategoryGoodsSerializer

    def get_queryset(self):
        # 随机取出几个分类
        import random
        category_id_list = self.queryset.values_list('id', flat=True)
        selected_ids = random.sample(list(category_id_list), 3)
        qs = self.queryset.filter(id__in=selected_ids)
        return qs

首先只获取一级分类,然后再随机选择其中3个显示在首页

添加首页分类商品路由

修改 DjangoOnlineFreshSupermarket/urls.py 添加

from goods.views import GoodsListView, GoodsListViewSet, CategoryViewSet, ParentCategoryViewSet, BannerViewSet, IndexCategoryGoodsViewSet


router.register(r'indexgoods', IndexCategoryGoodsViewSet, base_name='indexgoods')  # 首页分类及商品

现在访问 http://127.0.0.1:8000/indexgoods/?format=json 就可以看下序列化后的json格式数据

BLOG_20190814_135530_67

由于我们没有添加品牌的图片,所以值为空,之后再补充。

Vue首页分类商品接口联调

Vue中显示分类商品的组件在 src/views/index/series-list.vue ,组件创建时调用this.getList()方法

            getList() {
                queryCategorygoods()
                    .then((response) => {
                        //跳转到首页页response.body面
                        console.log('首页获取分类及商品数据');
                        console.log(response);
                        this.list = response.data
                    })
                    .catch(function (error) {
                        console.log(error);
                    });
            }

这时候会请求queryCategorygoods()函数,也就是访问接口

//获取商品类别信息
export const queryCategorygoods = params => {
    return axios.get(`${local_host}/indexgoods/`)
};

得到数据之后赋值给this.list进行遍历

这我先把 src/views/index/series-list.vue 的广告位注释掉了,否则数据循环可能会会报错

                <div class="series_pic">
                    广告位
                    <!--router-link :to="'/app/home/productDetail/'+items.ad_goods.id" target=_blank>
                        <img :src="items.ad_goods.goods_front_image" width="340" height="400">
                    </router-link-->
                </div>

接下来访问 http://127.0.0.1:8080/#/app/home/index 就能看到这些数据了

[外链图片转存失败(img-Uur9LbNm-1565762239403)(https://blog.starmeow.cn/media/blog/images/2019/08/BLOG_20190814_135521_91.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 “博客图集BLOG_20190814_135521_91.png”)]

按理说这些商品图片是显示不出来的,因为后端在序列化时,并没有加上域名。之后测试。

BLOG_20190814_135515_34

首页类别中的广告位和品牌图片

首页类别广告模型

在 apps/goods/models.py 创建一个新的模型

class IndexCategoryAd(models.Model):
    """
    首页广告
    """
    category = models.ForeignKey(GoodsCategory, null=True, blank=True, on_delete=models.CASCADE, verbose_name='商品类别', help_text='商品类别', related_name='ads')
    goods = models.ForeignKey(Goods, verbose_name='商品', help_text='商品', on_delete=models.CASCADE, related_name='ads')
    add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')

    class Meta:
        verbose_name_plural = verbose_name = '首页类别广告'

    def __str__(self):
        return self.category

添加完成后记得执行makemigrationsmigrate

后台类别广告添加一些数据

修改 apps/goods/admin.py 注册广告的models

from .models import GoodsCategory, Goods, GoodsImage, IndexCategoryAd

@admin.register(IndexCategoryAd)
class IndexCategoryAdAdmin(admin.ModelAdmin):
    list_display = ['category', 'goods']

访问Django后台 http://127.0.0.1:8000/admin/goods/indexcategoryad/add/ 添加一些广告位商品,一定要添加到一级分类下

BLOG_20190814_135508_53

后台类别广告中category过滤

当选择商品类别时,会显示所有级别的类别,如果想只显示一级分类,修改 apps/goods/admin.py 中的IndexCategoryAdAdmin

@admin.register(IndexCategoryAd)
class IndexCategoryAdAdmin(admin.ModelAdmin):
    list_display = ['category', 'goods']

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'category':
            # 外键下拉框添加过滤
            kwargs['queryset'] = GoodsCategory.objects.filter(category_type=1)
        return super(IndexCategoryAdAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

BLOG_20190814_135503_52

序列化广告位商品

修改 apps/goods/serializers.py

# 首页分类商品序列化
class IndexCategoryGoodsSerializer(serializers.ModelSerializer):
    brands = BrandsSerializer(many=True)  # 分类下的品牌图片
    # goods = GoodsSerializer(many=True)  # 不能这样用,因为现在需要的是一级分类,而大多数商品是放在三级分类中的,所以很多商品是取不到的,所以到自己查询一级分类子类别下的所有商品
    goods = serializers.SerializerMethodField()
    sub_category = CategorySerializer2(many=True)  # 序列化二级分类
    ad_goods = serializers.SerializerMethodField()  # 广告商品可能加了很多,取每个分类第一个

    def get_ad_goods(self, obj):
        all_ads = obj.ads.all()
        if all_ads:
            ad = all_ads.first().goods  # 获取到商品分类对应的商品
            ad_serializer = GoodsSerializer(ad)  # 序列化该广告商品
            return ad_serializer.data
        else:
            # 在该分类没有广告商品时,必须要返回空字典,否则Vue中取obj.id会报错
            return {}

    def get_goods(self, obj):
        # 查询每级分类下的所有商品
        all_goods = Goods.objects.filter(Q(category_id=obj.id) | Q(category__parent_category_id=obj.id) | Q(category__parent_category__parent_category_id=obj.id))
        # 将查询的商品集进行序列化
        goods_serializer = GoodsSerializer(all_goods, many=True)
        # 返回json对象
        return goods_serializer.data

    class Meta:
        model = GoodsCategory
        fields = '__all__'

接下来访问 http://127.0.0.1:8000/indexgoods/?format=json 就可以显示广告商品的数据了

BLOG_20190814_135456_70

后台品牌图片增加一些数据

访问Django后台 http://127.0.0.1:8000/admin/goods/goodscategorybrand/ 随意添加一些数据到一级分类下

BLOG_20190814_135445_19

也可以按照首页类别广告的后台注册代码,对商品类别就行过滤。

Vue和广告商品联调

修改Vue主页组件 src/views/index/series-list.vue 将广告位取消注释

                <div class="series_pic">
                    <router-link :to="'/app/home/productDetail/'+items.ad_goods.id" target=_blank>
                        <img :src="items.ad_goods.goods_front_image" width="340" height="400">
                    </router-link>
                </div>

[外链图片转存失败(img-vvErSSVo-1565762239404)(https://blog.starmeow.cn/media/blog/images/2019/08/BLOG_20190814_135436_36.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 “博客图集BLOG_20190814_135436_36.png”)]

由于只添加了部分数据,所有很多都没有显示完整。

序列化嵌套序列化商品图片url加上域名

示例序列化的结果:商品图片goods_front_image: "/media/upload/goods_init/images/1_P_1449024889889.jpg",没有加上域名

将 proxy.js 进行修改,改为一个不存在的地址,修改了需要重启服务器,最好清除浏览器缓存货隐身模式下测试

module.exports = {
    "/": "http://myserver.com:8001"  //如果部署服务器,需修改为服务器的域名
    //"/": "http://127.0.0.1:8000"
};

现在访问就出现破图了

[外链图片转存失败(img-mHvIdwSp-1565762239405)(https://blog.starmeow.cn/media/blog/images/2019/08/BLOG_20190814_135428_21.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 “博客图集BLOG_20190814_135428_21.png”)]

当我们的url没有域名,也就是类似"/media/upload/goods_init/images/1_P_1449024889889.jpg"的地址,就会自动加上 proxy.js 中配置的域名,所以之前能够正常显示。

在 apps/goods/serializers.py 的IndexCategoryGoodsSerializer中,也就是Serializer调用另一个Serializer是不会自动加上域名的,如果要加上域名,需要在嵌套的Serializer中添加一个参数context={'request': self.context['request']}

# 首页分类商品序列化
class IndexCategoryGoodsSerializer(serializers.ModelSerializer):
    brands = BrandsSerializer(many=True)  # 分类下的品牌图片
    # goods = GoodsSerializer(many=True)  # 不能这样用,因为现在需要的是一级分类,而大多数商品是放在三级分类中的,所以很多商品是取不到的,所以到自己查询一级分类子类别下的所有商品
    goods = serializers.SerializerMethodField()
    sub_category = CategorySerializer2(many=True)  # 序列化二级分类
    ad_goods = serializers.SerializerMethodField()  # 广告商品可能加了很多,取每个分类第一个

    def get_ad_goods(self, obj):
        all_ads = obj.ads.all()
        if all_ads:
            ad = all_ads.first().goods  # 获取到商品分类对应的商品
            ad_serializer = GoodsSerializer(ad, context={'request': self.context['request']})  # 序列化该广告商品,嵌套的序列化类中添加context参数,可在序列化时添加域名
            return ad_serializer.data
        else:
            # 在该分类没有广告商品时,必须要返回空字典,否则Vue中取obj.id会报错
            return {}

    def get_goods(self, obj):
        # 查询每级分类下的所有商品
        all_goods = Goods.objects.filter(Q(category_id=obj.id) | Q(category__parent_category_id=obj.id) | Q(category__parent_category__parent_category_id=obj.id))
        # 将查询的商品集进行序列化
        goods_serializer = GoodsSerializer(all_goods, many=True, context={'request': self.context['request']})
        # 返回json对象
        return goods_serializer.data

    class Meta:
        model = GoodsCategory
        fields = '__all__'

现在广告商品和分类商品的图片url已正常添加域名了

BLOG_20190814_135419_65

[外链图片转存失败(img-iqpYankq-1565762239405)(https://blog.starmeow.cn/media/blog/images/2019/08/BLOG_20190814_135414_15.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 “博客图集BLOG_20190814_135414_15.png”)]

加上这个context参数后,刷新页面,图片就正常显示了

[外链图片转存失败(img-E8nmxpQ8-1565762239405)(https://blog.starmeow.cn/media/blog/images/2019/08/BLOG_20190814_135409_15.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 “博客图集BLOG_20190814_135409_15.png”)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值