如何在Django中拼接两个QuerySet并写入xlwt格式Excel文件
问题根因
当前代码使用itertools.chain拼接两个QuerySet,会将Enrollment的查询结果作为独立行追加在Person数据之后,而非将对应Person行与Enrollment行合并为同一行,导致字段错位。同时原代码缺少return response语句,接口无法正常返回文件。
修正方案
根据模型关联关系可选择两种实现方式:
方式1:联表查询(推荐,适用于两表存在外键关联的场景)
假设Enrollment模型存在关联Person的外键字段person,直接通过ORM联表查询一次性获取所有字段,不存在行匹配错误风险:
import xlwt from django.http import HttpResponse def export_excel(request): response = HttpResponse(content_type='application/ms-excel') response['Content-Disposition'] = 'filename="persondatas.xls"' wb = xlwt.Workbook(encoding='utf-8') ws = wb.add_sheet('AllinOne') row_num = 0 font_style = xlwt.XFStyle() font_style.font.bold = True # 已修正原表头birthpace拼写错误为birthplace columns = ['name', 'fulname', 'id', 'gender', 'country', 'birthdate', 'birthplace', 'departament', 'feature'] for col_num in range(len(columns)): ws.write(row_num, col_num, columns[col_num], font_style) font_style = xlwt.XFStyle() # 外键反向引用字段名如果有自定义修改,同步调整enrollment__前缀后的字段名 rows = Person.objects.values_list( 'name', 'lastname', 'selfid', 'gender', 'country', 'dateofbirth', 'placeofbirth', 'enrollment__departament', 'enrollment__feature' ) for row in rows: row_num += 1 for col_num in range(len(row)): ws.write(row_num, col_num, str(row[col_num]) if row[col_num] is not None else '', font_style) wb.save(response) return response
方式2:行合并(适用于两表无关联、查询结果行数一一对应的场景)
如果两表无关联,但查询返回行数相同、顺序一一对应,使用zip_longest合并每行数据,行数不一致时自动补空值避免报错:
import xlwt from itertools import zip_longest from django.http import HttpResponse def export_excel(request): response = HttpResponse(content_type='application/ms-excel') response['Content-Disposition'] = 'filename="persondatas.xls"' wb = xlwt.Workbook(encoding='utf-8') ws = wb.add_sheet('AllinOne') row_num = 0 font_style = xlwt.XFStyle() font_style.font.bold = True columns = ['name', 'fulname', 'id', 'gender', 'country', 'birthdate', 'birthplace', 'departament', 'feature'] for col_num in range(len(columns)): ws.write(row_num, col_num, columns[col_num], font_style) font_style = xlwt.XFStyle() persons = Person.objects.values_list( 'name', 'lastname', 'selfid', 'gender', 'country', 'dateofbirth', 'placeofbirth' ) enrollments = Enrollment.objects.values_list('departament', 'feature') for person_row, job_row in zip_longest(persons, enrollments, fillvalue=()): row_num += 1 full_row = person_row + job_row for col_num in range(len(full_row)): ws.write(row_num, col_num, str(full_row[col_num]) if full_row[col_num] is not None else '', font_style) wb.save(response) return response
内容的提问来源于stack exchange,提问作者Zura Begadze
相关产品推荐
相关产品推荐

