专题: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 就能看到这些数据了
BLOG_20190814_135521_91按理说这些商品图片是显示不出来的,因为后端在序列化时,并没有加上域名。之后测试。
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
添加完成后记得执行makemigrations
和migrate
后台类别广告添加一些数据
修改 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>
BLOG_20190814_135436_36
由于只添加了部分数据,所有很多都没有显示完整。
序列化嵌套序列化商品图片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"
};
现在访问就出现破图了
BLOG_20190814_135428_21当我们的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 BLOG_20190814_135414_15加上这个context
参数后,刷新页面,图片就正常显示了
网友评论