从CSV/Excel导入数据填充Django Admin 外键关联异常问题求解
问题根源
你的原有代码存在几个核心错误导致无法得到预期结果:
- 仅读取了Excel第一行的
user字段对应的Account对象,后续所有行的session无法匹配到对应用户,且zip操作时如果Session行数大于Account查询结果行数,会直接截断多余的Session数据 - 存在语法错误:
print(models缺少闭合右括号 - 单条循环插入数据效率极低,数据量大会严重拖慢响应
- 没有异常校验,比如Excel中给出的邮箱不存在对应的Account时,会直接报错导致导入中断
最优实现方案
分为两种场景,你可以根据需求选择:
场景1:视图函数优化版
import pandas as pd from django.http import HttpResponse from .models import Account, GuidedSession from django.db import transaction def handle(request): # 读取Excel文件 df = pd.read_excel('testdata.xlsx') # 提前批量查询所有用到的Account缓存,避免循环查库降低性能 email_list = df['user'].unique().tolist() account_map = {acc.email: acc for acc in Account.objects.filter(email__in=email_list)} session_objs = [] error_rows = [] for index, row in df.iterrows(): # 校验对应用户是否存在 user_email = row['user'] if user_email not in account_map: error_rows.append(f"第{index+2}行:邮箱{user_email}不存在对应账户,跳过") continue # 构造GuidedSession对象 session_objs.append( GuidedSession( session_date=str(row['session_date']), session_time=str(row['session_time']), session_name=str(row['session_name']), duration=int(row['duration']), user=account_map[user_email] ) ) # 事务批量插入,要么全部成功要么全部失败,避免产生脏数据 with transaction.atomic(): GuidedSession.objects.bulk_create(session_objs) # 返回导入结果 if error_rows: return HttpResponse(f"导入完成,成功导入{len(session_objs)}条,失败{len(error_rows)}条:<br>" + "<br>".join(error_rows)) return HttpResponse(f"导入成功,共导入{len(session_objs)}条数据", status=200)
场景2:集成到Django Admin后台(更贴合需求)
如果你要直接在Django Admin后台操作导入,不需要单独写视图,直接给GuidedSession的Admin配置导入动作即可:
- 在你的
admin.py中添加如下代码:
from django.contrib import admin from .models import GuidedSession, Account import pandas as pd from django.db import transaction @admin.register(GuidedSession) class GuidedSessionAdmin(admin.ModelAdmin): list_display = ('session_name', 'session_date', 'session_time', 'duration', 'user') actions = ['bulk_import_from_excel'] def bulk_import_from_excel(self, request, queryset): df = pd.read_excel('testdata.xlsx') email_list = df['user'].unique().tolist() account_map = {acc.email: acc for acc in Account.objects.filter(email__in=email_list)} session_objs = [] error_rows = [] for index, row in df.iterrows(): user_email = row['user'] if user_email not in account_map: error_rows.append(f"第{index+2}行:邮箱{user_email}不存在对应账户,跳过") continue session_objs.append( GuidedSession( session_date=str(row['session_date']), session_time=str(row['session_time']), session_name=str(row['session_name']), duration=int(row['duration']), user=account_map[user_email] ) ) with transaction.atomic(): GuidedSession.objects.bulk_create(session_objs) if error_rows: self.message_user(request, f"导入完成,成功{len(session_objs)}条,失败{len(error_rows)}条:{','.join(error_rows)}", level='warning') else: self.message_user(request, f"导入成功,共{len(session_objs)}条") bulk_import_from_excel.short_description = "从Excel批量导入会话数据"
配置完成后打开Django Admin的GuidedSession列表页,在上方动作下拉框选择对应选项即可直接完成导入。
注意事项
- Excel必须包含
user列,存储对应用户的邮箱,和Account表的email字段匹配 bulk_create的插入效率比循环save高10倍以上,非常适合批量导入场景- 事务配置保证了数据一致性,不会出现导入一半报错、部分数据残留的问题
内容的提问来源于stack exchange,提问作者Hassan Sajjad
相关产品推荐
相关产品推荐

