Django导出模型数据到Excel时遇TypeError: expected <class 'float'>错误求助
解决TypeError: expected <class 'float'>错误(Django模型导出Excel)
我一眼就瞅出问题出在你设置列宽的代码上!咱们一步步拆解分析:
错误根源
你定义的columns是纯字段名字符串列表:
columns=['Id','Name','Image1','Image2','Date']
然后你写了这么一行代码:
ws.column_dimensions[get_column_letter(col_num + 1)].width = columns[col_num][1]
这里的columns[col_num][1]是取每个字段名的第二个字符(比如'Id'[1]就是'd'),这是个字符串类型,但openpyxl要求列宽必须是浮点数(float),直接赋值字符串自然就抛出了TypeError: expected <class 'float'>。
顺带提一句,你设置表头的代码c.value = columns[col_num][0]也有问题——这会把表头变成每个字段名的第一个字符(比如Name变成'N'),显然不是你想要的效果。
修复方案
你需要把字段名和对应列宽分开定义,用元组列表存储(每个元组存「字段名,列宽」),然后分别赋值:
核心代码修改
# 定义字段名+对应列宽的元组列表,列宽设置为你需要的浮点数 columns = [('Id', 10.0), ('Name', 20.0), ('Image1', 30.0), ('Image2', 30.0), ('Date', 15.0)] row_num = 0 for col_num in range(len(columns)): c = ws.cell(row=row_num + 1, column=col_num + 1) # 设置完整字段名为表头 c.value = columns[col_num][0] # 用浮点数设置列宽 ws.column_dimensions[get_column_letter(col_num + 1)].width = columns[col_num][1]
另外还有个小细节:你设置下载文件名的代码没闭合引号,要改成:
response['Content-Disposition'] = 'attachment; filename="users.xls"'
额外优化建议
- 直接导出
obj.Image1(FileField对象)的话,Excel里会显示类似<FieldFile: media/images/xxx.jpg>的字符串,如果你想显示文件路径或URL,可以改成obj.Image1.path(本地路径)或obj.Image1.url(访问URL),记得处理空值情况; - 日期字段
obj.Date会被openpyxl自动转为Excel日期格式,空值也会正常显示为空单元格,这部分没问题。
完整修正后的list方法代码
def list(self,request): try: queryset=Task.objects.all() response = HttpResponse(content_type='application/ms-excel') # 修复文件名引号闭合问题 response['Content-Disposition'] = 'attachment; filename="users.xls"' wb = openpyxl.Workbook() ws = wb.active ws.title = "Your Title" row_num=0 # 字段名+列宽的元组列表 columns = [('Id', 10.0), ('Name', 20.0), ('Image1', 30.0), ('Image2', 30.0), ('Date', 15.0)] for col_num in range(len(columns)): c = ws.cell(row=row_num + 1, column=col_num + 1) c.value = columns[col_num][0] ws.column_dimensions[get_column_letter(col_num + 1)].width = columns[col_num][1] for obj in queryset: row_num += 1 # 优化FileField显示内容,示例用URL,可按需换成path row = [ obj.Id, obj.Name, obj.Image1.url if obj.Image1 else "", obj.Image2.url if obj.Image2 else "", obj.Date, ] for col_num in range(len(row)): c = ws.cell(row=row_num + 1, column=col_num + 1) c.value = row[col_num] wb.save(response) return response except Exception as error: traceback.print_exc() return Response({"message": str(error), "success": False}, status=status.HTTP_200_OK)
这样修改后,你的导出功能就能正常运行啦!
内容的提问来源于stack exchange,提问作者Ashuosh Mishra




