如何将含外键的Django模型数据导出至CSV文件
解决Django模型导出CSV时外键仅显示ID的问题
嘿,我来帮你搞定这个外键导出的问题!你现在的代码能导出数据,但外键只显示ID,是因为values_list()默认只会获取外键字段存储的主键值。要把关联模型的具体信息也导出到同一行,有两种常用的方法,我给你详细说说:
方法一:用双下划线直接指定外键关联字段
Django的查询集支持用**双下划线(__)**来访问外键关联模型的字段,你可以直接在values_list()里指定这些字段,这样就能一次性拿到关联对象的具体值,不用额外循环处理。
修改后的视图代码
import csv from django.http import HttpResponse from .models import session def exportsCSV(request): # 提前用select_related拉取外键数据,避免N+1查询问题 sessions = session.objects.select_related('responden', 'mark', 'order').all() response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=sessions.csv' writer = csv.writer(response) # 先写入CSV表头(根据你的需求自定义字段名) writer.writerow([ 'ID', 'Responden信息', '认知分数', '社交分数', '身体分数', '总分', '开始时间', '结束时间', '时长', '标记信息', '顺序信息' ]) # 用双下划线指定外键的具体字段(这里假设responden有name字段,sessionMark有title字段,sessionOrder有number字段,你要换成自己模型的实际字段) sess_data = sessions.values_list( 'id', 'responden__name', # 访问responden模型的name字段 'kognitifScore', 'sosioScore', 'fisikScore', 'totalScore', 'timeStart', 'timeEnd', 'duration', 'mark__title', # 访问sessionMark模型的title字段 'order__number' # 访问sessionOrder模型的number字段 ) # 写入所有数据行 writer.writerows(sess_data) return response
方法二:手动遍历对象获取外键属性(更灵活)
如果你的外键可能为空,或者需要对关联字段做自定义处理(比如格式化显示),可以直接遍历每个session对象,手动构建每一行的数据,这样能更灵活地控制输出内容。
示例代码
import csv from django.http import HttpResponse from .models import session def exportsCSV(request): # 同样用select_related优化查询 sessions = session.objects.select_related('responden', 'mark', 'order').all() response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=sessions.csv' writer = csv.writer(response) # 写入表头 writer.writerow([ 'ID', 'Responden信息', '认知分数', '社交分数', '身体分数', '总分', '开始时间', '结束时间', '时长', '标记信息', '顺序信息' ]) # 逐个处理每个session对象 for sess in sessions: # 处理外键为空的情况,避免报错 responden_info = sess.responden.name if sess.responden else '无数据' mark_info = sess.mark.title if sess.mark else '无数据' order_info = sess.order.number if sess.order else '无数据' # 构建当前行的数据 row = [ sess.id, responden_info, sess.kognitifScore, sess.sosioScore, sess.fisikScore, sess.totalScore, sess.timeStart.strftime('%Y-%m-%d %H:%M:%S'), # 格式化时间 sess.timeEnd.strftime('%Y-%m-%d %H:%M:%S'), sess.duration, mark_info, order_info ] writer.writerow(row) return response
关键注意点
- 避免N+1查询问题:一定要在查询集里加上
select_related('responden', 'mark', 'order'),这样Django会一次性把关联的外键数据从数据库拉取出来,否则每次访问sess.responden都会触发新的数据库查询,数据量大会很慢。 - 替换实际字段名:上面代码里的
responden__name、mark__title等都是示例,你要换成自己responden、sessionMark、sessionOrder模型里实际存在的字段(比如姓名、状态、序号等)。 - 处理空值:如果外键字段允许为空(
null=True),记得像方法二那样做判断,避免出现AttributeError。
内容的提问来源于stack exchange,提问作者Andi Fathul Mukminin
相关产品推荐
相关产品推荐

