django model filter_我给我大姨用Django+Vue开发生鲜电商平台!在乡下也能网购了

一、首页功能完善

首页待完善的功能包括轮播图、新品尝鲜、系列商品等。

1.轮播图实现

轮播图包括3张图片,链接对应3个商品,先在apps/goods/serializers.py中定义序列化如下:

class BannerSerializer(serializers.ModelSerializer):    class Meta:        model = Banner        fields = '__all__'

再在views.py中定义视图如下:

class BannerViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):    '''    list:        轮播图列表    '''    queryset = Banner.objects.filter(is_delete=False).order_by('index')    serializer_class = BannerSerializer

再在urls.py中定义路由如下:

# 配置轮播图路由router.register(r'banners', BannerViewSet, basename='banners')

测试如下:

3bdc2a7a-f818-eb11-8da9-e4434bdf6706.png

可以看到,开始没有轮播图数据,经过在管理后台添加数据后,即同步数据。

前端src/views/index/banners.vue如下:

methods:{    getBanner(){    bannerGoods()        .then((response)=> {        console.log(response)        //跳转到首页页response.body面        this.banners = response.data        })        .catch(function (error) {        console.log(error);        });    }},created(){    this.getBanner();}

在初始化时调用getBanner()方法,在调用bannerGoods接口请求数据,请求到的数据再通过for循环展示出来。

api.js修改如下:

//获取轮播图export const bannerGoods = params => { return axios.get(`${local_host}/banners/`) }

此时再进行测试如下:

43dc2a7a-f818-eb11-8da9-e4434bdf6706.png

显然,请求的图片数据已从本地加载,并且点击轮播图片会调皮转到相应的商品链接。

2.新品功能开发

在定义商品模型时定义了is_new字段表示是否是新品,再实现新品功能时需要用到该字段,直接使用Goods接口并在filters.py过滤器中定义即可,如下:

class GoodsFilter(django_filters.rest_framework.FilterSet):    '''商品过滤类'''    name = django_filters.CharFilter(field_name="name", lookup_expr='contains')    pricemin = django_filters.NumberFilter(field_name="market_price", lookup_expr='gte')    pricemax = django_filters.NumberFilter(field_name="market_price", lookup_expr='lte')    top_category = django_filters.NumberFilter(method='top_category_filter')    def top_category_filter(self, queryset, name, value):        '''自定义过滤'''        return queryset.filter(Q(category_id=value)|Q(category__parent_category_id=value)|Q(category__parent_category__parent_category_id=value))    class Meta:        model = Goods        fields = ['name', 'pricemin', 'pricemax', 'is_hot', 'is_new']

演示如下:

46dc2a7a-f818-eb11-8da9-e4434bdf6706.png

显然,在手动添加新品之后,新品数据即同步,请求的参数中包含is_new=true。

前端src/views/index/news.vue如下:

    

{{item.name}}

{{item.goods_brief}}

¥{{item.shop_price}}元原价:¥{{item.market_price}}元 立即抢购 销量:{{item.sold_num}}件
methods:{ getOpro(){ getGoods({ "is_new":"true" }) .then((response)=> { //跳转到首页页response.body面 this.newopro = response.data.results }) .catch(function (error) { console.log(error); }); }},created(){ this.getOpro();}

可以看到,在初始化时,调用getOpro()方法,在调用getGoods接口时传入参数is_new,来获取新品,与之前获取商品调用的接口相同,获取到数据后通过for循环显示出来。

访问示意如下:

4edc2a7a-f818-eb11-8da9-e4434bdf6706.png

3.商品系列分类展示功能

商品系列分类包括左侧的导航栏和右侧的商品列表,大类对应多个品牌、大类对应多个小类、大类对应多个商品,即包含3个一对多关系,在定义序列化时需要嵌套定义

为了实现嵌套,在定义GoodsCategoryBrand模型时需要指定related_name属性,如下:

class GoodsCategoryBrand(models.Model):    '''品牌名'''    category = models.ForeignKey(GoodsCategory, verbose_name='商品类目', related_name='brands', null=True, on_delete=models.SET_NULL)    name = models.CharField(default='', max_length=30, verbose_name='品牌名', help_text='品牌名')    desc = models.TextField(default='', max_length=200, verbose_name='品牌描述', help_text='品牌描述')    image = models.ImageField(max_length=200, upload_to='brands/')    add_time = models.DateTimeField(default=datetime.now, verbose_name=u'添加时间')    is_delete = models.BooleanField(default=False, verbose_name='是否删除')    class Meta:        verbose_name = '品牌'        verbose_name_plural = verbose_name    def __str__(self):        return self.nameclass IndexAd(models.Model):    category = models.ForeignKey(GoodsCategory, verbose_name='商品类目', related_name='category', null=True, on_delete=models.SET_NULL)    goods = models.ForeignKey(Goods, verbose_name='商品', related_name='goods', null=True, on_delete=models.SET_NULL)    class Meta:        verbose_name = '首页商品类别广告'        verbose_name_plural = verbose_name    def __str__(self):        return self.goods.name

完成后需要进行数据映射。

为了在创建brand时只显示一级类别,在adminx.py中定义GoodsBrandAdmin类时重写了get_context()方法,其中获取到category字段只取category_type为1的数据,如下:

定义序列化如下:class BannerSerializer(serializers.ModelSerializer):    class Meta:        model = Banner        fields = '__all__'class BrandSerializer(serializers.ModelSerializer):    class Meta:        model = GoodsCategoryBrand        fields = '__all__'class IndexCategorySerializer(serializers.ModelSerializer):    brands = BrandSerializer(many=True)    goods = serializers.SerializerMethodField()    sub_cat = SecCategorySerializer(many=True)    ad_goods = serializers.SerializerMethodField()    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)        return goods_serializer.data    def get_ad_goods(self, obj):        goods_json = {}        ad_goods = IndexAd.objects.filter(category_id=obj.id)        if ad_goods:            good_instance = ad_goods[0].goods            goods_json = GoodsSerializer(good_instance, many=False).data        return goods_json    class Meta:        model = GoodsCategory        fields = '__all__'class GoodsBrandAdmin(object):    list_display = ["category", "image", "name", "desc"]    def get_context(self):        context = super(GoodsBrandAdmin, self).get_context()        if 'form' in context:            context['form'].fields['category'].queryset = GoodsCategory.objects.filter(category_type=1)        return context

定义序列化如下:

class BannerSerializer(serializers.ModelSerializer):    class Meta:        model = Banner        fields = '__all__'class BrandSerializer(serializers.ModelSerializer):    class Meta:        model = GoodsCategoryBrand        fields = '__all__'class IndexCategorySerializer(serializers.ModelSerializer):    brands = BrandSerializer(many=True)    goods = serializers.SerializerMethodField()    sub_cat = SecCategorySerializer(many=True)    ad_goods = serializers.SerializerMethodField()    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)        return goods_serializer.data    def get_ad_goods(self, obj):        goods_json = {}        ad_goods = IndexAd.objects.filter(category_id=obj.id)        if ad_goods:            good_instance = ad_goods[0].goods            goods_json = GoodsSerializer(good_instance, many=False).data        return goods_json    class Meta:        model = GoodsCategory        fields = '__all__'

可以看到,定义了多个一对多的关系和一个一对一的关系,视图如下:

定义路由如下:# 配置首页商品系列路由router.register(r'indexgoods', IndexCategoryViewSet, basename='indexgoods')class IndexCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):    '''    list:        商品分类数据    '''    queryset = GoodsCategory.objects.filter(is_delete=False, is_tab=True, name__in=['生鲜食品', '酒水饮料'])    serializer_class = IndexCategorySerializer

定义路由如下:

# 配置首页商品系列路由router.register(r'indexgoods', IndexCategoryViewSet, basename='indexgoods')

进行测试:

54dc2a7a-f818-eb11-8da9-e4434bdf6706.png

可以看到,再添加数据brands和ad_goods之前这两类数据为空,添加之后数据同步。

但是同时也可以看到,在商品的image属性的值即图片链接中未自动添加域名,这是因为进行嵌套序列化默认不会添加域名,需要给字段设置context属性,配置如下:

class IndexCategorySerializer(serializers.ModelSerializer):    brands = BrandSerializer(many=True)    goods = serializers.SerializerMethodField()    sub_cat = SecCategorySerializer(many=True)    ad_goods = serializers.SerializerMethodField()    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']})        return goods_serializer.data    def get_ad_goods(self, obj):        goods_json = {}        ad_goods = IndexAd.objects.filter(category_id=obj.id)        if ad_goods:            good_instance = ad_goods[0].goods            goods_json = GoodsSerializer(good_instance, many=False, context={'request': self.context['request']}).data        return goods_json    class Meta:        model = GoodsCategory        fields = '__all__'

此时再查看如下:

58dc2a7a-f818-eb11-8da9-e4434bdf6706.png

显然,已经将域名显示出来。

前端src/views/index/series-list.vue如下:

{{items.name}}

{{label.name}}

{{list.name}}

¥{{list.shop_price}}元

methods:{ getList(){ queryCategorygoods() .then((response)=> { //跳转到首页页response.body面 console.log(response) this.list = response.data }) .catch(function (error) { console.log(error); }); }},created(){ this.getList();}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值