Django前后端分离:实现一键从excel批量上传数据和图片到数据库

起因

最近在写一个和图片处理有关系的系统
结果甲方要求批量导入数据和图片
一琢磨,瞬间想到了excel,这玩意儿啥都能放,所以打算从这里上传
结果就遇到了很多问题
这个处理的过程其实很简单,大概是下面的思路

基本思路

  1. 前端界面:在前端页面中,提供一个上传Excel文件的表单,并在上传成功后,通过Ajax将文件发送到后端Django应用程序中。
  2. 后端逻辑:在Django应用程序中,编写视图函数来处理上传的Excel文件。可以使用Python库如pandas来读取Excel文件,并将数据转换为Django模型实例。
  3. 处理图片:在将Excel中的信息导入到Django模型实例之前,需要将图片从Excel中提取出来,并保存到Django的媒体文件夹中。可以使用Python库如openpyxl来处理Excel文件,并使用Django的FileField字段来保存图片。
  4. 数据库操作:将转换后的Django模型实例保存到数据库中。
  5. 返回结果:最后,将处理后的结果返回到前端,以便用户可以查看导入的信息和图片

在网上找了一些写法大致是这样的

采用Python openpyxl 提取 Excel 中的图片

前端代码(这个没啥问题)

<!-- 文件上传表单 -->
<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="file" name="file">
    <button type="submit">导入</button>
</form>
<!-- 用于显示导入结果的div -->
<div id="result"></div>

<!-- Ajax请求 -->
<script>
    $("form").submit(function (event) {
        event.preventDefault();
        var formData = new FormData($(this)[0]);
        $.ajax({
            url: "/import-data/",
            type: "POST",
            data: formData,
            processData: false,
            contentType: false,
            success: function (response) {
                $("#result").html(response);
            }
        });
    });
</script>

后端(有一句有大问题,后面细说

import openpyxl
from django.http import HttpResponse
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.views.decorators.csrf import csrf_exempt

from .models import MyModel

@csrf_exempt
def import_data(request):
    if request.method == "POST":
        # 读取上传的文件
        file = request.FILES.get("file")
        if not file:
            return HttpResponse("没有选择文件。")
        # 处理Excel文件
        wb = openpyxl.load_workbook(file)
        sheet = wb.active
        for row in sheet.iter_rows(min_row=2):
            name = row[0].value
            age = row[1].value
            picture = row[2].value
            # 处理图片
            picture_file = default_storage.save("pictures/" + picture.name, ContentFile(picture.read()))

            # 创建Django模型实例
            MyModel.objects.create(name=name, age=age, picture=picture_file)

        return HttpResponse("导入成功。")
    else:
        return HttpResponse("请求方法不允许。")

经过

没想到困住我的第一件事竟然是

什么才叫做单元格内有图片

离谱吧:一开始点击插入图片直接就出现在单元格里了,但这货能来回拖动,随便一拖动图片就出这个单元格了,经过最后的实验证明;不管图片在哪,只要插入的时候是在单元格内,就算是图片在单元格内了
为什么我会纠结这个呢
是因为这段代码

image = row[7].value

一直报错:

IndexError: tuple index out of range

所以我就以为是我的单元格内的没有图片。

解决办法

在查找和试过无数次的代码后,无意间发现了这段代码

import openpyxl as opx

wb = opx.load_workbook('Book1.xlsx')
ws = wb.active
ws._images[0] # 第一张图片对象
data = ws._images[0]._data() # 图片的字节数据

# 保存数据为图片
with open("image.png", "wb") as img:
    img.write(data)

在本地试了试,结果很顺利的存在了该项目的根目录下

那么问题出在那里呢?
没错,就是这句

data = ws._images[0]._data() # 图片的字节数据

在给出的代码中

image = row[7].value

有一个机制是, openpyxl 是不能读取图片的

在Excel中,图片存储在一个称为“二进制大对象”(Binary Large Object,简称BLOB)的单元格内。这个单元格包含一个指向实际图像文件所在位置的链接,并且还可能包括其他与该图像有关的属性,例如大小和位置等。当用户在Excel中查看或编辑工作表时,Excel会使用这些信息检索并显示相应的图像。

所以我们需要修改代码成这样

image = ws._images[row[0].row-1]._data()
//row[0].row代表这是第几个图片

解决

所以后端修改后的代码时这样的

import openpyxl
from django.http import HttpResponse
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.views.decorators.csrf import csrf_exempt
from .models import MyModel

@csrf_exempt
def import_data(request):
    if request.method == "POST":
        # 读取上传的文件
        file = request.FILES.get("file")
        if not file:
            return HttpResponse("没有选择文件。")
        # 处理Excel文件
        wb = openpyxl.load_workbook(file)
        sheet = wb.active
        for row in sheet.iter_rows(min_row=2):
            name = row[0].value
            age = row[1].value
            picture= ws._images[row[0].row-1]._data()
            # 处理图片
            picture_file = default_storage.save("pictures/" + picture.name, ContentFile(picture.read()))

            # 创建Django模型实例
            MyModel.objects.create(name=name, age=age, picture=picture_file)

        return HttpResponse("导入成功。")
    else:
        return HttpResponse("请求方法不允许。")

切记读有图片的单元格不要用row[1].value,
这句话读出来会显示越界:因为它读不到任何东西

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django实现前后端分离图片上传,可以通过以下步骤来完成: 1. 在前端页面中添加一个文件上传的表单,例如: ```html <form enctype="multipart/form-data" method="POST"> {% csrf_token %} <input type="file" name="image"> <button type="submit">上传</button> </form> ``` 2. 在 Django 后端中编写一个视图函数来处理图片上传请求,例如: ```python from django.http import JsonResponse def upload_image(request): if request.method == 'POST' and request.FILES['image']: image = request.FILES['image'] # 处理上传图片,例如保存到本地或上传到云存储 # ... # 返回上传结果 return JsonResponse({'status': 'success', 'url': 'http://example.com/path/to/image'}) else: return JsonResponse({'status': 'error', 'message': '上传失败'}) ``` 3. 在前端页面中使用 AJAX 技术将图片上传请求发送到后端,并在上传成功后显示上传结果,例如: ```javascript $('form').submit(function(event) { event.preventDefault(); var formData = new FormData(this); $.ajax({ url: '/upload_image/', type: 'POST', data: formData, processData: false, contentType: false, success: function(response) { if (response.status == 'success') { // 显示上传成功的图片 $('#image').attr('src', response.url); } else { alert('上传失败:' + response.message); } }, error: function(xhr, status, error) { alert('上传失败:' + error); } }); }); ``` 其中,`/upload_image/` 是后端处理图片上传请求的 URL,`FormData` 对象可以将表单数据序列化为一个 `multipart/form-data` 格式的字符串,`processData: false` 和 `contentType: false` 参数可以避免 jQuery 对表单数据进行默认的处理,从而实现上传文件的功能。上传成功后,可以通过 `response.url` 获取上传图片的 URL,并显示在页面上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值