Django项目中用openpyxl实现Excel双表头及内容排版问题
在Django里用openpyxl做符合要求的双表头Excel导出
要实现你要的双表头+组织信息和用户信息对应展示的效果,关键要抓两点:
- 搭好两层表头:第一层用合并单元格做分组标题,第二层写具体的字段名
- 处理组织和用户的关联数据:同一个组织的所有用户,对应的组织信息单元格要跨行合并,避免重复显示
调整后的完整代码
假设你的Organisation和User模型是通过外键关联的(比如User里有organisation外键字段),下面是可以直接用的导出代码:
from django.http import HttpResponse from openpyxl import Workbook from openpyxl.styles import Font, Alignment from openpyxl.utils import get_column_letter from openpyxl.styles.borders import Border, Side from .models import Organisation, User # 替换成你项目的模型导入路径 def export_org_users_excel(request): # 初始化工作簿和工作表 wb = Workbook() ws = wb.active ws.title = "组织用户信息" # 定义常用样式:加粗、居中、细边框 bold_font = Font(bold=True) center_align = Alignment(horizontal='center', vertical='center') thin_border = Border( left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin') ) # 第一层表头:分组标题(合并单元格) ws.merge_cells('A1:C1') org_group_cell = ws['A1'] org_group_cell.value = "组织信息" org_group_cell.font = bold_font org_group_cell.alignment = center_align ws.merge_cells('D1:F1') user_group_cell = ws['D1'] user_group_cell.value = "用户信息" user_group_cell.font = bold_font user_group_cell.alignment = center_align # 第二层表头:具体字段 field_headers = [ "组织名称", "注册日期", "语言", "名字", "姓氏", "邮箱" ] for col_num, header in enumerate(field_headers, 1): cell = ws.cell(row=2, column=col_num, value=header) cell.font = bold_font cell.alignment = center_align cell.border = thin_border # 填充数据并处理合并单元格 current_row = 3 # 获取你要导出的指定组织(替换成你的筛选逻辑,比如按ID取) target_orgs = Organisation.objects.all() # 示例:取所有组织,可改成get(pk=request.GET.get('org_id')) for org in target_orgs: users = org.user_set.all() # 关联用户,根据你的外键关系调整 if not users: continue # 组织信息需要合并的行数 = 当前组织的用户数量 merge_count = len(users) # 写入组织信息并合并单元格 # 组织名称 ws.merge_cells(f'A{current_row}:A{current_row + merge_count - 1}') name_cell = ws.cell(row=current_row, column=1, value=org.name) name_cell.alignment = center_align name_cell.border = thin_border # 注册日期(转成易读的字符串格式) ws.merge_cells(f'B{current_row}:B{current_row + merge_count - 1}') date_cell = ws.cell(row=current_row, column=2, value=org.signup_date.strftime("%Y-%m-%d")) date_cell.alignment = center_align date_cell.border = thin_border # 语言 ws.merge_cells(f'C{current_row}:C{current_row + merge_count - 1}') lang_cell = ws.cell(row=current_row, column=3, value=org.language) lang_cell.alignment = center_align lang_cell.border = thin_border # 逐个写入用户信息 for user in users: # 名字 ws.cell(row=current_row, column=4, value=user.first_name).border = thin_border # 姓氏 ws.cell(row=current_row, column=5, value=user.last_name).border = thin_border # 邮箱 ws.cell(row=current_row, column=6, value=user.email).border = thin_border current_row += 1 # 调整列宽,避免内容被截断 for col in range(1, 7): ws.column_dimensions[get_column_letter(col)].width = 20 # 生成响应,返回Excel文件 response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename="组织用户信息.xlsx"' wb.save(response) return response
关键调整说明
- 双表头结构:第一行用合并单元格区分“组织信息”和“用户信息”两个分组,第二行明确列出每个字段,完全匹配你要的双表头需求
- 组织信息合并:同一个组织的所有用户,对应的组织名称、注册日期、语言单元格会自动合并成一个大单元格,不会重复显示相同的组织信息
- 样式优化:给表头加粗、内容居中,加上细边框,让表格看起来更清晰易读
- 数据对应:每个用户的信息和所属组织的信息在同一行的不同列,完全符合你的预期展示逻辑
要注意的细节
- 把代码里的模型字段(比如
org.name、user.first_name)改成你项目里实际的字段名 - 如果不需要第一层的分组标题,可以直接删掉第一行合并单元格的代码,从第二行开始写所有字段表头就行
- 日期格式可以通过
strftime的参数调整成你想要的样式(比如"%m/%d/%Y")
内容的提问来源于stack exchange,提问作者Ilian Gion Häsler
相关产品推荐
相关产品推荐

