Django设计批量导入Excel数据接口(包含图片)

Django设计批量导入Excel数据接口(包含图片)

目录

示例xlsx文件

接口详情

前端上传FormData

随便弄个上传按钮即可

这里上传我用的是ElementUI自带的action(懒)

html 复制代码
<el-upload
    class="upload-Excel-demo"
    name="Excel_File"
    :action=$config.BASEURL+$config.ExcelUploadURL
    :with-credentials=true
    :on-success="handleSuccess"
    multiple
    :file-list="ExcelFileList">
  <el-button size="small">Excel批量导入</el-button>
</el-upload>

后端APIView

python 复制代码
class UploadExcelApiView(APIView):
    def post(self, request, *args, **kwargs):
        # 上传Excel文件
        excel_file = request.FILES.get('Excel_File', None)
        print(excel_file)
        # 验证文件格式
        file_extension = os.path.splitext(excel_file.name)[1]
        assert file_extension.lower() in ['.xlsx', '.xls'], "不支持的文件格式,请上传 .xlsx 或 .xls 文件"
        # 定义一个允许的字段字典
        allowed_fields = {'男/女': '', '款号': '', '产品类型': '', '针型': '', '克重': '', '材质': '', '针法': '',
                          '织机时间': '', '描述': '', '工艺师': '', '生产日期': '', '产品图片': ''}

        # 读取Excel文件并将每个sheet表格放入列表中
        wb = openpyxl.load_workbook(excel_file)
        sheet_list = [wb[sheet] for sheet in wb.sheetnames]

        # 定义临时变量 存储数据对象
        garment_knowledge_objects = []
        garment_image_objects = []
        try:
            for sheet in sheet_list:
                # 验证表头是否正确
                first_row = next(sheet.iter_rows(values_only=True))
                print(f'first_row: {first_row}')
                allowed_fields = xlsx_first_row_validator(allowed_fields, first_row)
                print(f'allowed_fields: {allowed_fields}')

                # 提取图片
                for img in sheet._images:
                    # 图片转base64 以便上传到服务器
                    img_file = xlsx_img_to_base64(img)
                    img_row = img.anchor._from.row  # 图片所在行
                    img_col = img.anchor._from.col  # 图片所在列

                    # 格式化数据
                    formatted_data = extract_and_format_date(
                        sheet.cell(row=img_row + 1, column=(first_row.index(allowed_fields['生产日期'])) + 1).value)
                    formatted_gender = format_gender_handler(
                        sheet.cell(row=img_row + 1, column=(first_row.index(allowed_fields['男/女'])) + 1).value)

                    product_id = sheet.cell(row=img_row + 1, column=(first_row.index(allowed_fields['款号'])) + 1).value
                    print(
                        f'正在上传{product_id}')
                    # GarmentKnowledge就是自己创建的模型类
                    g_obj, created = GarmentKnowledge.objects.update_or_create(
                        product_id=product_id,
                        defaults={
                            'user': request.user,
                            'product_type': sheet.cell(row=img_row + 1,
                                                       column=(first_row.index(allowed_fields['产品类型'])) + 1).value,
                            'needle_type': sheet.cell(row=img_row + 1,
                                                      column=(first_row.index(allowed_fields['针型'])) + 1).value,
                            'knitting_time': sheet.cell(row=img_row + 1,
                                                        column=(first_row.index(allowed_fields['织机时间'])) + 1).value,
                            'gram_weight': sheet.cell(row=img_row + 1,
                                                      column=(first_row.index(allowed_fields['克重'])) + 1).value,
                            'composition': sheet.cell(row=img_row + 1,
                                                      column=(first_row.index(allowed_fields['材质'])) + 1).value,
                            'technologist': sheet.cell(row=img_row + 1,
                                                       column=(first_row.index(allowed_fields['工艺师'])) + 1).value,
                            'description': sheet.cell(row=img_row + 1,
                                                      column=(first_row.index(allowed_fields['描述'])) + 1).value,
                            'manufactured_at': formatted_data,
                            'pattern': sheet.cell(row=img_row + 1,
                                                  column=(first_row.index(allowed_fields['针法'])) + 1).value,
                            'gender_type': formatted_gender,
                        }
                    )
                    img_obj = GarmentImagesFile(garment_knowledge=g_obj, image=img_file)
                    garment_knowledge_objects.append(g_obj)
                    garment_image_objects.append(img_obj)

            # 批量创建对象
            GarmentKnowledge.objects.bulk_create(garment_knowledge_objects)
            GarmentImagesFile.objects.bulk_create(garment_image_objects)
            print('上传成功')
        except Exception as e:
            print(f'错误信息:{e}')
            return APIResponse(code_msg='error', detail=e, data=None, status=status.HTTP_400_BAD_REQUEST)

        return APIResponse(code_msg='success', detail='上传成功', data=None, status=status.HTTP_200_OK)

调用函数

python 复制代码
import io
import re

from django.core.files.uploadedfile import InMemoryUploadedFile

def format_gender_handler(gender_str):
    if gender_str.lower() == '男':
        return '男装'
    elif gender_str.lower() == '女':
        return '女装'
    else:
        return None

def extract_and_format_date(date_str):
    date_str = str(date_str)
    # 使用正则表达式提取字符串中的第一个四位数年份、月份和日期
    match = re.search(r'(\d{4}).*?(\d{1,2}).*?(\d{1,2})', date_str)
    if match:
        year = match.group(1)  # 提取年份
        month = match.group(2).zfill(2)  # 提取月份,补全两位数
        day = match.group(3).zfill(2)  # 提取日期,补全两位数
        return f"{year}-{month}-{day}"
    else:
        raise ValueError("无法从输入中提取日期")


def xlsx_img_to_base64(img_obj):
    """
    img_obj必须是一个xlsx文件中的图片对象
    例:sheet._images
    """
    img_bytes = io.BytesIO(img_obj._data())
    img_bytes.seek(0)
    img_file = InMemoryUploadedFile(
        file=img_bytes,  # 图像字节流
        field_name=None,  # 字段名,保持为 None
        name='image.png',  # 使用图像对象的名字或默认名
        content_type='image/png',  # 根据实际图像格式设置内容类型
        size=img_bytes.getbuffer().nbytes,  # 获取图像字节大小
        charset=None  # 字符编码,通常不需要
    )
    return img_file


def xlsx_first_row_validator(allowed_fields, first_row):
    """
    first_row必须是一个由表头字段组成的可遍历对象
    例:('款号', '产品类型', '针型', '克重(克)', '材质', '针法')
    返回值allowed_fields将会更新为由规定字段和接收字段组成的字典
    例:{'款号': '款号', '产品类型': '产品类型', '针型': '针型', '克重': '克重'}

    """
    for first_cell in first_row:
        for key, value in allowed_fields.items():
            if key in first_cell or first_cell in key:
                allowed_fields[key] = first_cell
    return allowed_fields
        for key, value in allowed_fields.items():
            if key in first_cell or first_cell in key:
                allowed_fields[key] = first_cell
    return allowed_fields
相关推荐
程序员一诺41 分钟前
【Django开发】前后端分离django美多商城项目第15篇:商品搜索,1. Haystack介绍和安装配置【附代码文档】
后端·python·django·框架
安分小尧1 小时前
[特殊字符] 使用 Handsontable 构建一个支持 Excel 公式计算的动态表格
前端·javascript·react.js·typescript·excel
hello_simon5 小时前
在线小白工具,PPT转PDF支持多种热门工具,支持批量转换,操作简单,高效适合各种需求
pdf·html·powerpoint·excel·pdf转html·excel转pdf格式
Tttian6228 小时前
Python办公自动化(3)对Excel的操作
开发语言·python·excel
有趣的我13 小时前
vim的操作
编辑器·vim·excel
woniu_maggie14 小时前
SAP EXCEL DOI 详解
开发语言·后端·excel
小狗很可爱14 小时前
视图函数的应用
django
Dickson15 小时前
如何批量拆分Excel工作表或按行拆分Excel表格 - Excel拆分器使用方法
excel·excel拆分器·拆分excel·拆分excel工作表·按行拆分excel
麦麦大数据17 小时前
neo4j+django+deepseek知识图谱学习系统对接前后端分离前端vue
vue.js·django·知识图谱·neo4j·deepseek·在线学习系统
inxunoffice18 小时前
批量将文本文件转换为 Word/PDF/Excel/图片等其它格式
pdf·word·excel