简体中文 繁體中文 English 日本語 Deutsch 한국 사람 بالعربية TÜRKÇE português คนไทย Français

站内搜索

搜索

活动公告

11-02 12:46
10-23 09:32
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,将及时处理!
10-23 09:31
10-23 09:28
通知:签到时间调整为每日4:00(东八区)
10-23 09:26

Django Web应用中实现Excel数据导出功能的详细教程

3万

主题

424

科技点

3万

积分

大区版主

木柜子打湿

积分
31917

三倍冰淇淋无人之境【一阶】财Doro小樱(小丑装)立华奏以外的星空【二阶】⑨的冰沙

发表于 2025-9-24 15:40:16 | 显示全部楼层 |阅读模式 [标记阅至此楼]

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在Web应用开发中,数据导出功能是一项常见且重要的需求。无论是生成报表、数据备份还是提供数据分析素材,将数据导出为Excel格式都是用户友好的选择。本教程将详细介绍在Django Web应用中实现Excel数据导出的各种方法,从基础到高级,帮助开发者根据项目需求选择最合适的方案。

准备工作

在开始实现Excel导出功能之前,我们需要准备一些必要的库和工具。根据所选的实现方法,可能需要安装以下Python包:

基本库

• xlwt:用于创建和写入.xls格式的Excel文件(兼容旧版Excel)
• openpyxl:用于处理.xlsx格式的Excel文件(新版Excel)
• xlsxwriter:功能强大的.xlsx文件写入库

高级库

• pandas:强大的数据分析库,提供便捷的Excel导出功能
• django-import-export:Django第三方包,提供数据导入导出功能

安装必要的库
  1. # 安装基本库
  2. pip install xlwt openpyxl xlsxwriter
  3. # 安装高级库
  4. pip install pandas django-import-export
复制代码

基本实现方法:使用csv模块

虽然CSV不是Excel格式,但它是实现数据导出的最简单方法,并且Excel可以直接打开CSV文件。

创建视图函数
  1. import csv
  2. from django.http import HttpResponse
  3. def export_csv(request):
  4.     # 创建HttpResponse对象,设置content_type为'text/csv'
  5.     response = HttpResponse(content_type='text/csv')
  6.     response['Content-Disposition'] = 'attachment; filename="data_export.csv"'
  7.    
  8.     # 创建CSV写入器
  9.     writer = csv.writer(response)
  10.    
  11.     # 写入表头
  12.     writer.writerow(['ID', 'Name', 'Email', 'Date Joined'])
  13.    
  14.     # 从数据库获取数据并写入CSV
  15.     users = User.objects.all()
  16.     for user in users:
  17.         writer.writerow([user.id, user.username, user.email, user.date_joined])
  18.    
  19.     return response
复制代码

配置URL

在urls.py中添加URL配置:
  1. from django.urls import path
  2. from .views import export_csv
  3. urlpatterns = [
  4.     path('export-csv/', export_csv, name='export_csv'),
  5. ]
复制代码

添加导出按钮

在模板中添加导出按钮:
  1. <a href="{% url 'export_csv' %}" class="btn btn-primary">导出CSV</a>
复制代码

基本实现方法:使用xlwt库

xlwt是一个用于创建.xls格式Excel文件的库,适合处理简单的数据导出需求。

创建视图函数
  1. import xlwt
  2. from django.http import HttpResponse
  3. def export_xls(request):
  4.     # 创建HttpResponse对象,设置content_type为Excel格式
  5.     response = HttpResponse(content_type='application/ms-excel')
  6.     response['Content-Disposition'] = 'attachment; filename="data_export.xls"'
  7.    
  8.     # 创建Workbook对象
  9.     workbook = xlwt.Workbook(encoding='utf-8')
  10.    
  11.     # 添加工作表
  12.     worksheet = workbook.add_sheet('Users')
  13.    
  14.     # 设置表头样式
  15.     font = xlwt.Font()
  16.     font.bold = True
  17.     style = xlwt.XFStyle()
  18.     style.font = font
  19.    
  20.     # 写入表头
  21.     columns = ['ID', 'Name', 'Email', 'Date Joined']
  22.     for col_num, column in enumerate(columns):
  23.         worksheet.write(0, col_num, column, style)
  24.    
  25.     # 从数据库获取数据并写入Excel
  26.     users = User.objects.all()
  27.     for row_num, user in enumerate(users, 1):
  28.         worksheet.write(row_num, 0, user.id)
  29.         worksheet.write(row_num, 1, user.username)
  30.         worksheet.write(row_num, 2, user.email)
  31.         worksheet.write(row_num, 3, str(user.date_joined))
  32.    
  33.     # 保存工作簿到HttpResponse对象
  34.     workbook.save(response)
  35.    
  36.     return response
复制代码

配置URL
  1. from django.urls import path
  2. from .views import export_xls
  3. urlpatterns = [
  4.     path('export-xls/', export_xls, name='export_xls'),
  5. ]
复制代码

添加导出按钮
  1. <a href="{% url 'export_xls' %}" class="btn btn-primary">导出Excel (XLS)</a>
复制代码

高级实现方法:使用openpyxl库

openpyxl是一个功能强大的库,用于处理.xlsx格式的Excel文件,支持更多高级功能。

创建视图函数
  1. import openpyxl
  2. from openpyxl.styles import Font, Alignment, PatternFill
  3. from django.http import HttpResponse
  4. def export_xlsx(request):
  5.     # 创建HttpResponse对象,设置content_type为Excel格式
  6.     response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  7.     response['Content-Disposition'] = 'attachment; filename="data_export.xlsx"'
  8.    
  9.     # 创建Workbook对象
  10.     workbook = openpyxl.Workbook()
  11.    
  12.     # 获取活动工作表
  13.     worksheet = workbook.active
  14.     worksheet.title = "Users"
  15.    
  16.     # 定义表头样式
  17.     header_font = Font(name='Arial', size=12, bold=True)
  18.     header_fill = PatternFill(start_color='4F81BD', end_color='4F81BD', fill_type='solid')
  19.     header_alignment = Alignment(horizontal='center', vertical='center')
  20.    
  21.     # 写入表头
  22.     headers = ['ID', 'Name', 'Email', 'Date Joined']
  23.     for col_num, header in enumerate(headers, 1):
  24.         cell = worksheet.cell(row=1, column=col_num)
  25.         cell.value = header
  26.         cell.font = header_font
  27.         cell.fill = header_fill
  28.         cell.alignment = header_alignment
  29.    
  30.     # 调整列宽
  31.     for col_num, header in enumerate(headers, 1):
  32.         column_letter = openpyxl.utils.get_column_letter(col_num)
  33.         worksheet.column_dimensions[column_letter].width = 20
  34.    
  35.     # 从数据库获取数据并写入Excel
  36.     users = User.objects.all()
  37.     for row_num, user in enumerate(users, 2):
  38.         worksheet.cell(row=row_num, column=1, value=user.id)
  39.         worksheet.cell(row=row_num, column=2, value=user.username)
  40.         worksheet.cell(row=row_num, column=3, value=user.email)
  41.         worksheet.cell(row=row_num, column=4, value=str(user.date_joined))
  42.    
  43.     # 保存工作簿到HttpResponse对象
  44.     workbook.save(response)
  45.    
  46.     return response
复制代码

配置URL
  1. from django.urls import path
  2. from .views import export_xlsx
  3. urlpatterns = [
  4.     path('export-xlsx/', export_xlsx, name='export_xlsx'),
  5. ]
复制代码

添加导出按钮
  1. <a href="{% url 'export_xlsx' %}" class="btn btn-primary">导出Excel (XLSX)</a>
复制代码

高级实现方法:使用pandas库

pandas是一个强大的数据分析库,提供了便捷的Excel导出功能,特别适合处理复杂的数据结构。

创建视图函数
  1. import pandas as pd
  2. from django.http import HttpResponse
  3. def export_pandas_excel(request):
  4.     # 从数据库获取数据
  5.     users = User.objects.all().values('id', 'username', 'email', 'date_joined')
  6.    
  7.     # 转换为DataFrame
  8.     df = pd.DataFrame(list(users))
  9.    
  10.     # 重命名列
  11.     df.columns = ['ID', 'Name', 'Email', 'Date Joined']
  12.    
  13.     # 创建HttpResponse对象
  14.     response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  15.     response['Content-Disposition'] = 'attachment; filename="data_export.xlsx"'
  16.    
  17.     # 使用ExcelWriter写入Excel
  18.     with pd.ExcelWriter(response, engine='openpyxl') as writer:
  19.         df.to_excel(writer, sheet_name='Users', index=False)
  20.         
  21.         # 获取工作表对象以进行格式化
  22.         worksheet = writer.sheets['Users']
  23.         
  24.         # 调整列宽
  25.         for column in worksheet.columns:
  26.             max_length = 0
  27.             column_letter = column[0].column_letter
  28.             for cell in column:
  29.                 try:
  30.                     if len(str(cell.value)) > max_length:
  31.                         max_length = len(str(cell.value))
  32.                 except:
  33.                     pass
  34.             adjusted_width = (max_length + 2)
  35.             worksheet.column_dimensions[column_letter].width = adjusted_width
  36.    
  37.     return response
复制代码

配置URL
  1. from django.urls import path
  2. from .views import export_pandas_excel
  3. urlpatterns = [
  4.     path('export-pandas/', export_pandas_excel, name='export_pandas_excel'),
  5. ]
复制代码

添加导出按钮
  1. <a href="{% url 'export_pandas_excel' %}" class="btn btn-primary">导出Excel (Pandas)</a>
复制代码

使用Django第三方包:django-import-export

django-import-export是一个强大的Django第三方包,提供了数据导入导出功能,支持多种格式,包括Excel。

安装和配置

首先安装django-import-export:
  1. pip install django-import-export
复制代码

然后在settings.py中添加到INSTALLED_APPS:
  1. INSTALLED_APPS = [
  2.     # ...
  3.     'import_export',
  4. ]
复制代码

创建资源类

在应用的admin.py或新建的resources.py文件中创建资源类:
  1. from import_export import resources
  2. from .models import User
  3. class UserResource(resources.ModelResource):
  4.     class Meta:
  5.         model = User
  6.         fields = ('id', 'username', 'email', 'date_joined')
复制代码

创建视图函数
  1. from import_export import fields
  2. from django.http import HttpResponse
  3. from .resources import UserResource
  4. def export_import_export(request):
  5.     # 创建资源实例
  6.     user_resource = UserResource()
  7.    
  8.     # 获取数据集
  9.     dataset = user_resource.export()
  10.    
  11.     # 创建HttpResponse对象
  12.     response = HttpResponse(dataset.xlsx, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  13.     response['Content-Disposition'] = 'attachment; filename="data_export.xlsx"'
  14.    
  15.     return response
复制代码

配置URL
  1. from django.urls import path
  2. from .views import export_import_export
  3. urlpatterns = [
  4.     path('export-import-export/', export_import_export, name='export_import_export'),
  5. ]
复制代码

添加导出按钮
  1. <a href="{% url 'export_import_export' %}" class="btn btn-primary">导出Excel (Import-Export)</a>
复制代码

处理大数据量导出

当需要导出大量数据时,直接将所有数据加载到内存中可能会导致内存不足或响应超时。以下是几种处理大数据量导出的方法:

使用流式响应
  1. import openpyxl
  2. from django.http import StreamingHttpResponse
  3. class Echo:
  4.     """An object that implements just the write method of the file-like interface."""
  5.     def write(self, value):
  6.         return value
  7. def export_large_data(request):
  8.     # 创建StreamingHttpResponse对象
  9.     response = StreamingHttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  10.     response['Content-Disposition'] = 'attachment; filename="large_data_export.xlsx"'
  11.    
  12.     # 创建工作簿
  13.     workbook = openpyxl.Workbook()
  14.     worksheet = workbook.active
  15.     worksheet.title = "Large Data"
  16.    
  17.     # 写入表头
  18.     headers = ['ID', 'Name', 'Email', 'Date Joined']
  19.     for col_num, header in enumerate(headers, 1):
  20.         worksheet.cell(row=1, column=col_num, value=header)
  21.    
  22.     # 使用分页获取数据
  23.     batch_size = 1000
  24.     for start in range(0, User.objects.count(), batch_size):
  25.         users = User.objects.all()[start:start+batch_size]
  26.         for row_num, user in enumerate(users, start + 2):
  27.             worksheet.cell(row=row_num, column=1, value=user.id)
  28.             worksheet.cell(row=row_num, column=2, value=user.username)
  29.             worksheet.cell(row=row_num, column=3, value=user.email)
  30.             worksheet.cell(row=row_num, column=4, value=str(user.date_joined))
  31.    
  32.     # 保存工作簿到临时文件
  33.     import tempfile
  34.     with tempfile.NamedTemporaryFile() as tmp:
  35.         workbook.save(tmp.name)
  36.         tmp.seek(0)
  37.         response.write(tmp.read())
  38.    
  39.     return response
复制代码

使用生成器分批处理
  1. import openpyxl
  2. from django.http import HttpResponse
  3. def generate_excel_data():
  4.     # 创建工作簿
  5.     workbook = openpyxl.Workbook()
  6.     worksheet = workbook.active
  7.     worksheet.title = "Large Data"
  8.    
  9.     # 写入表头
  10.     headers = ['ID', 'Name', 'Email', 'Date Joined']
  11.     for col_num, header in enumerate(headers, 1):
  12.         worksheet.cell(row=1, column=col_num, value=header)
  13.    
  14.     # 使用分页获取数据
  15.     batch_size = 1000
  16.     for start in range(0, User.objects.count(), batch_size):
  17.         users = User.objects.all()[start:start+batch_size]
  18.         for row_num, user in enumerate(users, start + 2):
  19.             worksheet.cell(row=row_num, column=1, value=user.id)
  20.             worksheet.cell(row=row_num, column=2, value=user.username)
  21.             worksheet.cell(row=row_num, column=3, value=user.email)
  22.             worksheet.cell(row=row_num, column=4, value=str(user.date_joined))
  23.    
  24.     # 保存工作簿到字节流
  25.     from io import BytesIO
  26.     output = BytesIO()
  27.     workbook.save(output)
  28.     output.seek(0)
  29.    
  30.     return output.getvalue()
  31. def export_large_data_generator(request):
  32.     response = HttpResponse(
  33.         generate_excel_data(),
  34.         content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  35.     )
  36.     response['Content-Disposition'] = 'attachment; filename="large_data_export.xlsx"'
  37.    
  38.     return response
复制代码

添加样式和格式

使导出的Excel文件更加美观和专业,可以通过添加样式和格式来实现。

使用openpyxl添加样式
  1. import openpyxl
  2. from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
  3. from django.http import HttpResponse
  4. def export_styled_excel(request):
  5.     # 创建HttpResponse对象
  6.     response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  7.     response['Content-Disposition'] = 'attachment; filename="styled_export.xlsx"'
  8.    
  9.     # 创建工作簿
  10.     workbook = openpyxl.Workbook()
  11.     worksheet = workbook.active
  12.     worksheet.title = "Styled Data"
  13.    
  14.     # 定义样式
  15.     # 表头样式
  16.     header_font = Font(name='Arial', size=12, bold=True, color='FFFFFF')
  17.     header_fill = PatternFill(start_color='4F81BD', end_color='4F81BD', fill_type='solid')
  18.     header_alignment = Alignment(horizontal='center', vertical='center')
  19.    
  20.     # 边框样式
  21.     thin_border = Border(
  22.         left=Side(style='thin'),
  23.         right=Side(style='thin'),
  24.         top=Side(style='thin'),
  25.         bottom=Side(style='thin')
  26.     )
  27.    
  28.     # 数据样式
  29.     data_font = Font(name='Arial', size=10)
  30.     data_alignment = Alignment(horizontal='left', vertical='center')
  31.    
  32.     # 写入表头
  33.     headers = ['ID', 'Name', 'Email', 'Date Joined']
  34.     for col_num, header in enumerate(headers, 1):
  35.         cell = worksheet.cell(row=1, column=col_num)
  36.         cell.value = header
  37.         cell.font = header_font
  38.         cell.fill = header_fill
  39.         cell.alignment = header_alignment
  40.         cell.border = thin_border
  41.    
  42.     # 调整行高
  43.     worksheet.row_dimensions[1].height = 25
  44.    
  45.     # 调整列宽
  46.     for col_num, header in enumerate(headers, 1):
  47.         column_letter = openpyxl.utils.get_column_letter(col_num)
  48.         worksheet.column_dimensions[column_letter].width = 20
  49.    
  50.     # 从数据库获取数据并写入Excel
  51.     users = User.objects.all()
  52.     for row_num, user in enumerate(users, 2):
  53.         # ID单元格
  54.         id_cell = worksheet.cell(row=row_num, column=1, value=user.id)
  55.         id_cell.font = data_font
  56.         id_cell.alignment = data_alignment
  57.         id_cell.border = thin_border
  58.         
  59.         # Name单元格
  60.         name_cell = worksheet.cell(row=row_num, column=2, value=user.username)
  61.         name_cell.font = data_font
  62.         name_cell.alignment = data_alignment
  63.         name_cell.border = thin_border
  64.         
  65.         # Email单元格
  66.         email_cell = worksheet.cell(row=row_num, column=3, value=user.email)
  67.         email_cell.font = data_font
  68.         email_cell.alignment = data_alignment
  69.         email_cell.border = thin_border
  70.         
  71.         # Date Joined单元格
  72.         date_cell = worksheet.cell(row=row_num, column=4, value=str(user.date_joined))
  73.         date_cell.font = data_font
  74.         date_cell.alignment = data_alignment
  75.         date_cell.border = thin_border
  76.         
  77.         # 设置日期格式
  78.         date_cell.number_format = 'YYYY-MM-DD HH:MM:SS'
  79.    
  80.     # 添加条件格式
  81.     from openpyxl.styles import Color, PatternFill
  82.     from openpyxl.formatting.rule import CellIsRule
  83.    
  84.     # 为ID大于10的行添加背景色
  85.     red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
  86.     worksheet.conditional_formatting.add(
  87.         f'A2:A{users.count()+1}',
  88.         CellIsRule(operator='greaterThan', formula=['10'], fill=red_fill)
  89.     )
  90.    
  91.     # 添加表格样式
  92.     from openpyxl.worksheet.table import Table, TableStyleInfo
  93.     tab = Table(displayName="Table1", ref=f"A1:D{users.count()+1}")
  94.    
  95.     style = TableStyleInfo(
  96.         name="TableStyleMedium9",
  97.         showFirstColumn=False,
  98.         showLastColumn=False,
  99.         showRowStripes=True,
  100.         showColumnStripes=True
  101.     )
  102.     tab.tableStyleInfo = style
  103.     worksheet.add_table(tab)
  104.    
  105.     # 保存工作簿到HttpResponse对象
  106.     workbook.save(response)
  107.    
  108.     return response
复制代码

实际应用案例:完整的用户数据导出系统

让我们创建一个完整的用户数据导出系统,包括筛选、排序和自定义字段选择功能。

创建表单类
  1. from django import forms
  2. from django.contrib.auth.models import User
  3. class UserExportForm(forms.Form):
  4.     # 字段选择
  5.     FIELD_CHOICES = (
  6.         ('id', 'ID'),
  7.         ('username', 'Username'),
  8.         ('email', 'Email'),
  9.         ('first_name', 'First Name'),
  10.         ('last_name', 'Last Name'),
  11.         ('date_joined', 'Date Joined'),
  12.         ('last_login', 'Last Login'),
  13.         ('is_active', 'Is Active'),
  14.         ('is_staff', 'Is Staff'),
  15.     )
  16.    
  17.     fields = forms.MultipleChoiceField(
  18.         choices=FIELD_CHOICES,
  19.         widget=forms.CheckboxSelectMultiple,
  20.         initial=['id', 'username', 'email', 'date_joined']
  21.     )
  22.    
  23.     # 排序选项
  24.     SORT_CHOICES = (
  25.         ('id', 'ID'),
  26.         ('username', 'Username'),
  27.         ('email', 'Email'),
  28.         ('date_joined', 'Date Joined'),
  29.     )
  30.    
  31.     sort_by = forms.ChoiceField(choices=SORT_CHOICES, initial='id')
  32.     sort_order = forms.ChoiceField(
  33.         choices=(('asc', 'Ascending'), ('desc', 'Descending')),
  34.         initial='asc'
  35.     )
  36.    
  37.     # 格式选择
  38.     FORMAT_CHOICES = (
  39.         ('csv', 'CSV'),
  40.         ('xls', 'Excel (XLS)'),
  41.         ('xlsx', 'Excel (XLSX)'),
  42.     )
  43.    
  44.     format = forms.ChoiceField(choices=FORMAT_CHOICES, initial='xlsx')
  45.    
  46.     # 筛选选项
  47.     is_active = forms.BooleanField(required=False, initial=True)
  48.     is_staff = forms.BooleanField(required=False)
  49.     date_joined_after = forms.DateTimeField(required=False, help_text="YYYY-MM-DD HH:MM:SS")
  50.     date_joined_before = forms.DateTimeField(required=False, help_text="YYYY-MM-DD HH:MM:SS")
复制代码

创建视图函数
  1. import csv
  2. import xlwt
  3. import openpyxl
  4. from django.http import HttpResponse
  5. from django.contrib.auth.models import User
  6. from .forms import UserExportForm
  7. def export_users(request):
  8.     if request.method == 'POST':
  9.         form = UserExportForm(request.POST)
  10.         if form.is_valid():
  11.             # 获取表单数据
  12.             fields = form.cleaned_data['fields']
  13.             sort_by = form.cleaned_data['sort_by']
  14.             sort_order = form.cleaned_data['sort_order']
  15.             export_format = form.cleaned_data['format']
  16.             is_active = form.cleaned_data['is_active']
  17.             is_staff = form.cleaned_data['is_staff']
  18.             date_joined_after = form.cleaned_data['date_joined_after']
  19.             date_joined_before = form.cleaned_data['date_joined_before']
  20.             
  21.             # 构建查询集
  22.             queryset = User.objects.all()
  23.             
  24.             # 应用筛选条件
  25.             if is_active is not None:
  26.                 queryset = queryset.filter(is_active=is_active)
  27.             
  28.             if is_staff is not None:
  29.                 queryset = queryset.filter(is_staff=is_staff)
  30.             
  31.             if date_joined_after:
  32.                 queryset = queryset.filter(date_joined__gte=date_joined_after)
  33.             
  34.             if date_joined_before:
  35.                 queryset = queryset.filter(date_joined__lte=date_joined_before)
  36.             
  37.             # 应用排序
  38.             sort_prefix = '-' if sort_order == 'desc' else ''
  39.             queryset = queryset.order_by(f"{sort_prefix}{sort_by}")
  40.             
  41.             # 根据选择的格式导出
  42.             if export_format == 'csv':
  43.                 return export_users_csv(queryset, fields)
  44.             elif export_format == 'xls':
  45.                 return export_users_xls(queryset, fields)
  46.             elif export_format == 'xlsx':
  47.                 return export_users_xlsx(queryset, fields)
  48.     else:
  49.         form = UserExportForm()
  50.    
  51.     return render(request, 'export_users.html', {'form': form})
  52. def export_users_csv(queryset, fields):
  53.     response = HttpResponse(content_type='text/csv')
  54.     response['Content-Disposition'] = 'attachment; filename="users_export.csv"'
  55.    
  56.     writer = csv.writer(response)
  57.    
  58.     # 写入表头
  59.     writer.writerow(fields)
  60.    
  61.     # 写入数据
  62.     for user in queryset:
  63.         row = []
  64.         for field in fields:
  65.             value = getattr(user, field)
  66.             # 处理日期时间字段
  67.             if hasattr(value, 'strftime'):
  68.                 value = value.strftime('%Y-%m-%d %H:%M:%S')
  69.             row.append(value)
  70.         writer.writerow(row)
  71.    
  72.     return response
  73. def export_users_xlsx(queryset, fields):
  74.     response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  75.     response['Content-Disposition'] = 'attachment; filename="users_export.xlsx"'
  76.    
  77.     workbook = openpyxl.Workbook()
  78.     worksheet = workbook.active
  79.     worksheet.title = "Users"
  80.    
  81.     # 定义表头样式
  82.     header_font = Font(name='Arial', size=12, bold=True)
  83.     header_fill = PatternFill(start_color='4F81BD', end_color='4F81BD', fill_type='solid')
  84.     header_alignment = Alignment(horizontal='center', vertical='center')
  85.    
  86.     # 写入表头
  87.     for col_num, field in enumerate(fields, 1):
  88.         cell = worksheet.cell(row=1, column=col_num)
  89.         cell.value = field.replace('_', ' ').title()
  90.         cell.font = header_font
  91.         cell.fill = header_fill
  92.         cell.alignment = header_alignment
  93.    
  94.     # 调整列宽
  95.     for col_num in range(1, len(fields) + 1):
  96.         column_letter = openpyxl.utils.get_column_letter(col_num)
  97.         worksheet.column_dimensions[column_letter].width = 20
  98.    
  99.     # 写入数据
  100.     for row_num, user in enumerate(queryset, 2):
  101.         for col_num, field in enumerate(fields, 1):
  102.             value = getattr(user, field)
  103.             cell = worksheet.cell(row=row_num, column=col_num, value=value)
  104.             
  105.             # 处理日期时间字段
  106.             if hasattr(value, 'strftime'):
  107.                 cell.number_format = 'YYYY-MM-DD HH:MM:SS'
  108.    
  109.     workbook.save(response)
  110.     return response
复制代码

创建模板
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <title>Export Users</title>
  5.     <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
  6. </head>
  7. <body>
  8.     <div class="container mt-5">
  9.         <h1 class="mb-4">Export Users</h1>
  10.         
  11.         <form method="post">
  12.             {% csrf_token %}
  13.             
  14.             <div class="card mb-4">
  15.                 <div class="card-header">
  16.                     <h5 class="mb-0">Fields to Export</h5>
  17.                 </div>
  18.                 <div class="card-body">
  19.                     <div class="row">
  20.                         {% for field in form.fields %}
  21.                         <div class="col-md-4 mb-3">
  22.                             <div class="form-check">
  23.                                 {{ field.tag }}
  24.                                 <label class="form-check-label" for="{{ field.id_for_label }}">
  25.                                     {{ field.choice_label }}
  26.                                 </label>
  27.                             </div>
  28.                         </div>
  29.                         {% endfor %}
  30.                     </div>
  31.                 </div>
  32.             </div>
  33.             
  34.             <div class="card mb-4">
  35.                 <div class="card-header">
  36.                     <h5 class="mb-0">Export Format</h5>
  37.                 </div>
  38.                 <div class="card-body">
  39.                     <div class="row">
  40.                         <div class="col-md-12 mb-3">
  41.                             {% for radio in form.format %}
  42.                             <div class="form-check form-check-inline">
  43.                                 {{ radio.tag }}
  44.                                 <label class="form-check-label" for="{{ radio.id_for_label }}">
  45.                                     {{ radio.choice_label }}
  46.                                 </label>
  47.                             </div>
  48.                             {% endfor %}
  49.                         </div>
  50.                     </div>
  51.                 </div>
  52.             </div>
  53.             
  54.             <div class="d-grid gap-2 d-md-flex justify-content-md-end">
  55.                 <button type="submit" class="btn btn-primary">Export Users</button>
  56.             </div>
  57.         </form>
  58.     </div>
  59.    
  60.     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
  61. </body>
  62. </html>
复制代码

配置URL
  1. from django.urls import path
  2. from .views import export_users
  3. urlpatterns = [
  4.     path('export-users/', export_users, name='export_users'),
  5. ]
复制代码

性能优化和注意事项

在实现Excel导出功能时,有一些性能优化和注意事项需要考虑:

1. 使用select_related和prefetch_related优化查询
  1. # 不推荐:可能导致N+1查询问题
  2. users = User.objects.all()
  3. # 推荐:使用select_related减少查询次数
  4. users = User.objects.select_related('profile').all()
  5. # 推荐:使用prefetch_related处理多对多关系
  6. users = User.objects.prefetch_related('groups').all()
复制代码

2. 使用分页处理大数据集
  1. from django.core.paginator import Paginator
  2. def export_large_dataset(request):
  3.     # 获取查询集
  4.     queryset = User.objects.all()
  5.    
  6.     # 创建分页器
  7.     paginator = Paginator(queryset, 1000)  # 每页1000条记录
  8.    
  9.     # 创建Excel工作簿
  10.     workbook = openpyxl.Workbook()
  11.     worksheet = workbook.active
  12.     worksheet.title = "Large Dataset"
  13.    
  14.     # 写入表头
  15.     headers = ['ID', 'Name', 'Email', 'Date Joined']
  16.     for col_num, header in enumerate(headers, 1):
  17.         worksheet.cell(row=1, column=col_num, value=header)
  18.    
  19.     # 分页处理数据
  20.     row_num = 2
  21.     for page_num in paginator.page_range:
  22.         page = paginator.page(page_num)
  23.         for user in page.object_list:
  24.             worksheet.cell(row=row_num, column=1, value=user.id)
  25.             worksheet.cell(row=row_num, column=2, value=user.username)
  26.             worksheet.cell(row=row_num, column=3, value=user.email)
  27.             worksheet.cell(row=row_num, column=4, value=str(user.date_joined))
  28.             row_num += 1
  29.    
  30.     # 创建HttpResponse对象
  31.     response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  32.     response['Content-Disposition'] = 'attachment; filename="large_dataset.xlsx"'
  33.    
  34.     # 保存工作簿到HttpResponse对象
  35.     workbook.save(response)
  36.    
  37.     return response
复制代码

3. 使用异步任务处理长时间运行的导出
  1. from celery import shared_task
  2. from django.core.mail import EmailMultiAlternatives
  3. from django.conf import settings
  4. import openpyxl
  5. import os
  6. from datetime import datetime
  7. @shared_task
  8. def generate_export_async(user_id, filters=None):
  9.     from django.contrib.auth.models import User
  10.    
  11.     # 获取用户
  12.     user = User.objects.get(id=user_id)
  13.    
  14.     # 构建查询集
  15.     queryset = User.objects.all()
  16.    
  17.     # 应用筛选条件
  18.     if filters:
  19.         if 'is_active' in filters:
  20.             queryset = queryset.filter(is_active=filters['is_active'])
  21.         if 'is_staff' in filters:
  22.             queryset = queryset.filter(is_staff=filters['is_staff'])
  23.         # 其他筛选条件...
  24.    
  25.     # 创建Excel工作簿
  26.     workbook = openpyxl.Workbook()
  27.     worksheet = workbook.active
  28.     worksheet.title = "Async Export"
  29.    
  30.     # 写入表头
  31.     headers = ['ID', 'Name', 'Email', 'Date Joined']
  32.     for col_num, header in enumerate(headers, 1):
  33.         worksheet.cell(row=1, column=col_num, value=header)
  34.    
  35.     # 写入数据
  36.     for row_num, user_obj in enumerate(queryset, 2):
  37.         worksheet.cell(row=row_num, column=1, value=user_obj.id)
  38.         worksheet.cell(row=row_num, column=2, value=user_obj.username)
  39.         worksheet.cell(row=row_num, column=3, value=user_obj.email)
  40.         worksheet.cell(row=row_num, column=4, value=str(user_obj.date_joined))
  41.    
  42.     # 生成文件名
  43.     timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
  44.     filename = f'user_export_{timestamp}.xlsx'
  45.     filepath = os.path.join(settings.MEDIA_ROOT, 'exports', filename)
  46.    
  47.     # 确保目录存在
  48.     os.makedirs(os.path.dirname(filepath), exist_ok=True)
  49.    
  50.     # 保存Excel文件
  51.     workbook.save(filepath)
  52.    
  53.     # 发送邮件通知用户
  54.     subject = 'Your export is ready'
  55.     download_url = f"{settings.SITE_URL}/media/exports/{filename}"
  56.     body = f"""
  57.     Hello {user.username},
  58.    
  59.     Your export is ready. You can download it from the following link:
  60.     {download_url}
  61.    
  62.     This link will expire in 7 days.
  63.    
  64.     Thank you,
  65.     The Team
  66.     """
  67.    
  68.     email = EmailMultiAlternatives(subject, body, settings.DEFAULT_FROM_EMAIL, [user.email])
  69.     email.send()
  70.    
  71.     return filepath
  72. def export_async_view(request):
  73.     if request.method == 'POST':
  74.         # 获取筛选条件
  75.         filters = {
  76.             'is_active': request.POST.get('is_active') == 'on',
  77.             'is_staff': request.POST.get('is_staff') == 'on',
  78.             # 其他筛选条件...
  79.         }
  80.         
  81.         # 启动异步任务
  82.         task = generate_export_async.delay(request.user.id, filters)
  83.         
  84.         # 显示消息
  85.         messages.success(request, 'Your export is being processed. You will receive an email when it is ready.')
  86.         
  87.         return redirect('export_users')
  88.    
  89.     return render(request, 'export_async.html')
复制代码

4. 注意事项

• 内存使用:导出大量数据时,注意内存使用情况,避免内存溢出。
• 超时处理:长时间运行的导出可能导致请求超时,考虑使用异步任务或流式响应。
• 文件大小:大文件下载可能对服务器和用户都是挑战,考虑压缩文件或提供分块下载。
• 安全性:确保只有授权用户可以访问导出功能,特别是敏感数据。
• 数据格式:注意日期、数字等特殊数据类型的格式化,确保在Excel中正确显示。
• 字符编码:处理多语言数据时,确保使用正确的字符编码(通常是UTF-8)。

总结

本教程详细介绍了在Django Web应用中实现Excel数据导出功能的多种方法,从基础的CSV导出到高级的样式定制和大数据处理。我们探讨了以下几种主要实现方式:

1. 使用Python内置的csv模块导出CSV文件
2. 使用xlwt库导出XLS格式的Excel文件
3. 使用openpyxl库导出XLSX格式的Excel文件
4. 使用pandas库进行高级数据导出
5. 使用django-import-export第三方包简化导入导出功能

根据项目需求和数据规模,开发者可以选择最适合的方案。对于简单的导出需求,csv模块或xlwt库可能足够;对于需要格式化和样式的高级导出,openpyxl或xlsxwriter是更好的选择;对于复杂的数据处理和分析,pandas提供了强大的功能;而对于需要同时支持导入和导出的应用,django-import-export是一个成熟的解决方案。

通过本教程,开发者应该能够在Django应用中实现各种复杂度的Excel导出功能,满足不同的业务需求。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

频道订阅

频道订阅

加入社群

加入社群

联系我们|TG频道|RSS

Powered by Pixtech

© 2025 Pixtech Team.