保存图片数据
在保存数据之前我们需要先获取图片关联的sku的id
1、获取sku表id
接口分析
请求方式: GET /meiduo_admin/skus/simple/
# -------获取sku的id--------
url(r'skus/simple/$', images.ImageView.as_view({'get': 'simple'})),
请求参数: 通过请求头传递jwt token数据。
返回数据: JSON
[
{
"id": 1,
"name": "Apple MacBook Pro 13.3英寸笔记本 银色"
},
{
"id": 2,
"name": "Apple MacBook Pro 13.3英寸笔记本 深灰色"
},
......
]
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
Id | int | 是 | sku商品id |
name | 数组 | 是 | Sku商品名称 |
后端实现
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import ModelViewSet
from meiduo_admin.serializers.images import ImageSeriazlier, SKUSeriazlier
from goods.models import SKUImage, SKU
from meiduo_admin.utils import UserPageNum
from rest_framework.response import Response
class ImageView(ModelViewSet):
# 图片序列化器
serializer_class = ImageSeriazlier
# 图片查询集
queryset = SKUImage.objects.all()
# 分页
pagination_class = UserPageNum
permission_classes = [IsAdminUser]
# 获取sku商品信息
def simple(self, request):
# 查询所有的sku商品
data = SKU.objects.all()
# 序列化操作返回
ser = SKUSeriazlier(data, many=True)
return Response(ser.data)
序列化器的定义
from goods.models import SKU
class SKUSeriazlier(serializers.ModelSerializer):
class Meta:
model=SKU
fields=('id','name')
2、保存图片数据
接口分析
请求方式:POST /meiduo_admin/skus/images/
# 图片查询路由****************************
router = DefaultRouter()
router.register('skus/images', images.ImageView, base_name='images')
# print(router.urls)
urlpatterns += router.urls
请求参数: 通过请求头传递jwt token数据。
表单提交数据:
"sku": "SKU商品id",
"image": "SKU商品图片"
参数 | 类型 | 是否必须 | 说明 |
---|---|---|---|
sku | str | 是 | SKU商品id |
image | Fiel | 是 | SKU商品图片 |
返回数据: JSON
{
"id": "图片id",
"sku": "SKU商品id",
"image": "图片地址"
}
参数 | 类型 | 是否必须 | 说明 |
---|---|---|---|
id | Int | 是 | 图片id |
sku | int | 是 | SKU商品id |
image | str | 是 | 图片地址 |
后端实现
在保存图片的同时,我们还需要异步生成新的详情页页面,这是我们需要定义异步任务
【后端人员修改图片后,执行静态页面更改图片时可能速度会慢一些,所以防止阻塞这儿要使用异步任务】
import os
from django.conf import settings
from django.shortcuts import render
from meiduo_mall.utils.categories import get_categories
from meiduo_mall.utils.breadcrumb import get_breadcrumb
from goods.models import SKU
from celery_tasks.main import app
@app.task(name='get_detail_html')
def get_detail_html(sku_id):
# 获取当前sku对象
sku = SKU.objects.get(id=sku_id)
# 分类数据
categories = get_categories()
# 获取面包屑导航
breadcrumb = get_breadcrumb(sku.category)
# 获取spu
spu = sku.spu
# 获取规格信息:sku===>spu==>specs
specs = spu.specs.order_by('id')
# 查询所有的sku,如华为P10的所有库存商品
skus = spu.skus.order_by('id')
'''
{
选项:sku_id
}
说明:键的元组中,规格的索引是固定的
示例数据如下:
{
(1,3):1,
(2,3):2,
(1,4):3,
(2,4):4
}
'''
sku_options = {}
sku_option = []
for sku1 in skus:
infos = sku1.specs.order_by('spec_id')
option_key = []
for info in infos:
option_key.append(info.option_id)
# 获取当前商品的规格信息
if sku.id == sku1.id:
sku_option.append(info.option_id)
sku_options[tuple(option_key)] = sku1.id
# 遍历当前spu所有的规格
specs_list = []
for index, spec in enumerate(specs):
option_list = []
for option in spec.options.all():
# 如果当前商品为蓝、64,则列表为[2,3]
sku_option_temp = sku_option[:]
# 替换对应索引的元素:规格的索引是固定的[1,3]
sku_option_temp[index] = option.id
# 为选项添加sku_id属性,用于在html中输出链接
option.sku_id = sku_options.get(tuple(sku_option_temp), 0)
# 添加选项对象
option_list.append(option)
# 为规格对象添加选项列表
spec.option_list = option_list
# 重新构造规格数据
specs_list.append(spec)
context = {
'sku': sku,
'categories': categories,
'breadcrumb': breadcrumb,
'category_id': sku.category_id,
'spu': spu,
'specs': specs_list
}
response = render(None, 'detail.html', context)
file_name = os.path.join(settings.BASE_DIR, 'static/detail/%d.html' % sku.id)
# 写文件
with open(file_name, 'w') as f1:
f1.write(response.content.decode())
视图代码
在settings中配置fastdfs文件路径:
# 指定fastdfs文件路径
FASTDFS_PATH = os.path.join(BASE_DIR, 'utils/fdfs/client.conf')
images.py
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import ModelViewSet
from meiduo_admin.serializers.images import ImageSerializer, SKUSerializer
from goods.models import SKUImage, SKU
from meiduo_admin.utils import UserPageNum
from rest_framework.response import Response
from fdfs_client.client import Fdfs_client
from django.conf import settings
from celery_tasks.static_file.tasks import get_detail_html
class ImageView(ModelViewSet):
# 图片序列化器
serializer_class = ImageSerializer
# 图片查询集
queryset = SKUImage.objects.all()
# 分页
pagination_class = UserPageNum
# permission_classes = [IsAdminUser]
# 获取sku商品信息
def simple(self, request):
# 查询所有的sku商品
data = SKU.objects.all()
# 序列化操作返回
ser = SKUSerializer(data, many=True)
return Response(ser.data)
# 重写拓展类的保存业务逻辑
def create(self, request, *args, **kwargs):
# 创建FastDFS连接对象
client = Fdfs_client(settings.FASTDFS_PATH)
# 获取前端传递的image文件
data = request.FILES.get('image')
# 上传图片到fastDFS
res = client.upload_by_buffer(data.read())
# 判断是否上传成功
if res['Status'] != 'Upload successed.':
return Response(status=403)
# 获取上传后的路径
image_url = res['Remote file_id']
# 获取sku_id
sku_id = request.data.get('sku')[0]
# 保存图片
img = SKUImage.objects.create(sku_id=sku_id, image=image_url)
# 生成新的详情页页面
get_detail_html.delay(img.sku.id)
# 返回结果
return Response(
{
'id': img.id,
'sku': sku_id,
'image': img.image.url # 这儿返回是完整的路由信息
},
status=201 # 前端需要接受201状态
)
【上面的create方法可以封装到序列化器中的,具体操作可以看源码。其实这些代码在序列化器中写好后,这些代码是可以直接注释掉的,父类方法中已经提供了这些操作。在序列化器中是没有request属性的,可以使用self.context['request']代替】
修改后的代码:
序列化器:【视图中的create代码可以都注释掉了】
from rest_framework import serializers
from goods.models import SKUImage
from goods.models import SKU
from rest_framework.response import Response
from fdfs_client.client import Fdfs_client
from django.conf import settings
from celery_tasks.static_file.tasks import get_detail_html
class ImageSerializer(serializers.ModelSerializer):
# 返回图片关联的sku的id值
sku = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = SKUImage
# fields = ('sku', 'image', 'id')
fields = '__all__'
def create(self, validated_data):
# 创建FastDFS连接对象
client = Fdfs_client(settings.FASTDFS_PATH)
# 获取前端传来的image文件
data = self.context['request'].FILES.get('image')
# data = request.data
# 上传图片到fastDFS
res = client.upload_by_buffer(data.read())
# 判断是否上传成功
if res['Status'] != 'Upload successed.':
return Response(status=403)
# 获取上传后的路径
image_url = res['Remote file_id']
# 获取sku_id
sku_id = self.context['request'].data.get('sku')[0]
# 保存图片
img = SKUImage.objects.create(sku_id=sku_id, image=image_url)
# 异步生成详情页静态页面
get_detail_html.delay(img.sku.id)
return img
注意事项:这儿可能不能直接安装fdfs-client,这儿可以使用提前准备好的安装包文件,pip install fdfs-client-py-master.zip
关于FastDFS客户端上传文件以及安装各个注意事件,查看博文:
https://blog.csdn.net/weixin_44799217/article/details/118463124