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从入门到实战》专栏!关注不迷路~

相关推荐
come1123410 分钟前
深入Spring Boot的核心——配置管理(指南四)
java·spring boot·后端
come1123435 分钟前
深入分析JAR和WAR包的区别 (指南七)
android·spring boot·后端
每天进步一点_JL1 小时前
深入理解 volatile
后端
李慕婉学姐1 小时前
【开题答辩过程】以《基于SpringBoot+Vue的扶贫助农平台的设计与实现》为例,不会开题答辩的可以进来看看
vue.js·spring boot·后端
王嘉俊9251 小时前
Redis 入门:高效缓存与数据存储的利器
java·数据库·redis·后端·spring·缓存·springboot
aricvvang1 小时前
一行 Promise.all 争议:数据库查询并行真的没用?我和同事吵赢了!!!
javascript·后端·node.js
啦啦9117141 小时前
Print Conductor打印软件安装教程!一款非常好用的批量打印软件!支持PDF、Word、Excel、图片等
pdf·excel
文心快码BaiduComate2 小时前
Comate分饰多角:全栈开发一个Python学习网站
前端·后端·python
道可到2 小时前
淘宝面试原题 Java 面试通关笔记 02|从编译到运行——Java 背后的计算模型(面试可复述版)
java·后端·面试
SimonKing2 小时前
GitHub 标星 370k!免费编程资源大合集,从此自学不花一分钱
java·后端·程序员