图片管理之保存图片数据

保存图片数据

在保存数据之前我们需要先获取图片关联的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英寸笔记本 深灰色"
        },
        ......
    ]
返回值类型是否必须说明
Idintsku商品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商品图片"
参数类型是否必须说明
skustrSKU商品id
imageFielSKU商品图片

返回数据: JSON

 {
        "id": "图片id",
        "sku": "SKU商品id",
        "image": "图片地址"
    }
参数类型是否必须说明
idInt图片id
skuintSKU商品id
imagestr图片地址

后端实现

在保存图片的同时,我们还需要异步生成新的详情页页面,这是我们需要定义异步任务

【后端人员修改图片后,执行静态页面更改图片时可能速度会慢一些,所以防止阻塞这儿要使用异步任务】

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值