Django实战:基于Django和openpyxl实现Excel导入导出功能

一、openpyxl 介绍

openpyxl 是一个用于读取和写入 Excel 2010 xlsx/xlsm/xltx/xltm 文件的 Python 库。使用场景包括:

  • 数据分析:从 Excel 文件中读取数据,进行处理和分析。
  • 自动化办公:自动生成报告、填写表格等。
  • 数据导入导出:将数据从 Python 程序导入到 Excel,或将 Excel 数据导入到 Python 程序中。

安装openpyxl

sh 复制代码
pip install openpyxl

二、Excel文件下载

创建并保存 Excel 文件

示例:创建一个新的 Excel 工作簿,并写入一些数据,最后保存为文件

python 复制代码
from openpyxl import Workbook

# 创建一个新的工作簿
workbook = Workbook()

# 获取默认的工作表
sheet = workbook.active
sheet.title = "MySheet"  # 设置工作表标题

# 写入数据到单元格
sheet['A1'] = "Hello, Openpyxl!"
sheet['B2'] = 42

# 保存工作簿
workbook.save('new_example.xlsx')

Excel工具函数

为提高代码复用率,整理处理Excel工具函数

  • create_excel_workbook():将数据 data 按照指定字段和标签写入一个新的 Excel 工作簿,并设置表头和列宽。
  • generate_excel_response():将 workbook(Excel 工作簿)生成 Excel 文件,并通过 HTTP 响应返回给客户端下载
  • process_item():将一个数据项 item 按照指定字段顺序 fields 转换为一行数据(列表)
  • convert_datetime():将带有时区信息的 ISO 格式时间字符串(如 "2023-01-01T12:34:56.789+08:00")转换为去除时区、毫秒并替换 T 为空格的字符串,输出格式为 "YYYY-MM-DD HH:MM:SS"
python 复制代码
from urllib.parse import quote
from django.http import HttpResponse
from openpyxl import Workbook
from openpyxl.utils import get_column_letter


def convert_datetime(datetime_str):
    # 移除时区部分(+08:00)
    datetime_without_tz = datetime_str.replace("+08:00", "")
    # 移除 "T" 并截取到秒部分(去掉毫秒)
    return datetime_without_tz.replace("T", " ").split(".")[0]


def process_item(item, fields, data_map={}):
    """将单个数据项转换为行数据"""
    row = []
    for field in fields:
        value = item.get(field)
        # 友好显示转换
        if field in data_map:
            value = data_map[field].get(value, None)
        # 特殊字段类型转换
        elif field == "id" or field == "job_id":
            value = str(value)
        elif field == "create_time" or field == "date_created" or field == "date_done":
            value = convert_datetime(value)
        row.append(value)
    return row


def create_excel_workbook(data, fields_labels, data_map={}, sheet_name="Sheet1"):
    """
    将数据写入Excel文件
    """
    fields = list(fields_labels.keys())
    labels = list(fields_labels.values())
    # 创建一个 Excel 工作簿
    workbook = Workbook()
    sheet = workbook.active
    sheet.title = sheet_name
    # 设置表头
    sheet.append(labels)
    # 添加数据
    for item in data:
        row = process_item(item, fields, data_map)
        sheet.append(row)
    # 设置列宽
    for col_num in range(1, len(labels) + 1):
        col_letter = get_column_letter(col_num)
        sheet.column_dimensions[col_letter].width = 15

    return workbook


def generate_excel_response(workbook, file_name="export.xlsx"):
    """
    生成 Excel 文件并返回 HTTP 响应。
    """
    response = HttpResponse(
        content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    )
    response["Content-Disposition"] = f"attachment; filename={quote(file_name)}"
    workbook.save(response)
    return response

点击查看完整代码

项目实战:Excel文件下载

实战场景:在Django+Vue3后台管理系统中,实现用户的导入导出功能是常见需求。用户导入功能,一般需要先下载模板,填写后再导入。

实战代码:定义视图,将示例数据导出为 Excel 文件并返回给用户下载,实现下载模板功能

python 复制代码
  @extend_schema(summary="获得用户导入模板")
    @action(
        methods=["get"],
        detail=False,
        url_path="get-import-template",
    )
    def get_import_template(self, request, *args, **kwargs):
        """获得用户导入模板"""

        # 定义示例数据
        data = [
            {
                "username": "xiaozhang",
                "nickname": "小张",
                "deptId": "103",
                "email": "xz@qq.com",
                "mobile": "13312345670",
                "sex": "男",
                "status": "开启",
            },
            {
                "username": "xiaoli",
                "nickname": "小李",
                "deptId": "",
                "email": "",
                "mobile": "",
                "sex": "",
                "status": "关闭",
            },
        ]

        fields_labels = {
            "username": "用户账号",
            "nickname": "用户昵称",
            "deptId": "部门编号",
            "email": "用户邮箱",
            "mobile": "手机号码",
            "sex": "用户性别",
            "status": "账号状态",
        }

        # 返回工作簿
        workbook = create_excel_workbook(data, fields_labels)
        return generate_excel_response(workbook, "用户导入模板.xlsx")

实现效果

三、Excel 文件上传

获取上传的文件

当 Django 处理文件上传时,文件数据会被放置在 request.FILES 中。获取上传文件示例

python 复制代码
file = request.FILES.get("file")

读取Excel中的数据

示例:读取example.xlsx文件中的标题、单元格等信息

python 复制代码
from openpyxl import load_workbook

# 加载一个已存在的Excel文件
workbook = load_workbook('example.xlsx')

# 获取工作簿中的工作表
sheet = workbook.active  # 获取当前活动的工作表
print(sheet.title)  # 输出工作表的标题

# 读取单元格的值
cell_value = sheet['A1'].value
print(cell_value)

项目实战:Excel文件上传

实战场景:在Django+Vue3后台管理系统中,实现用户导入功能

  • 第一步:获取用户上传的文件
  • 第二步:调用get_user_import_data()函数,读取Excel文件中的用户数据,并将其转换为系统所需格式的字典列表。
  • 第三步:使用序列化器,将用户信息保存到数据库
python 复制代码
def get_user_import_data(file) -> list:
    """
    读取Excel文件中的用户信息,并将其转换为字典列表
    """
    # 加载Excel文件
    workbook = load_workbook(file)
    sheet = workbook.active
    # 固定表头,以确保数据字段的一致性
    headers = ["username", "nickname", "deptId", "email", "mobile", "sex", "status"]
    # 初始化数据列表
    data = []
    # 遍历每一行数据
    for row in sheet.iter_rows(min_row=2, values_only=True):
        # 将当前行数据与表头 zip 后转换为字典
        user_data = dict(zip(headers, row))
        # 转换 sex 和 status 字段
        user_data["sex"] = (
            1 if user_data["sex"] == "男" else 2 if user_data["sex"] == "女" else 0
        )
        user_data["status"] = (
            0
            if user_data["status"] == "开启"
            else 1 if user_data["status"] == "关闭" else None
        )
        data.append(user_data)

    return data

实现效果:点击查看完整代码


您正在阅读的是《Django从入门到实战》专栏!关注不迷路~

相关推荐
Victor3562 分钟前
Redis(6)Redis的单线程模型是如何工作的?
后端
Victor3563 分钟前
Redis(7)Redis如何实现高效的内存管理?
后端
Full Stack Developme1 小时前
Java后台生成多个Excel并用Zip打包下载
java·开发语言·excel
David爱编程1 小时前
进程 vs 线程到底差在哪?一文吃透操作系统视角与 Java 视角的关键差异
后端
smileNicky11 小时前
SpringBoot系列之从繁琐配置到一键启动之旅
java·spring boot·后端
David爱编程12 小时前
为什么必须学并发编程?一文带你看懂从单线程到多线程的演进史
java·后端
long31612 小时前
java 策略模式 demo
java·开发语言·后端·spring·设计模式
rannn_11113 小时前
【Javaweb学习|黑马笔记|Day1】初识,入门网页,HTML-CSS|常见的标签和样式|标题排版和样式、正文排版和样式
css·后端·学习·html·javaweb
柏油14 小时前
Spring @Cacheable 解读
redis·后端·spring
柏油14 小时前
Spring @TransactionalEventListener 解读
spring boot·后端·spring