You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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配置导入动作即可:

  1. 在你的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 15:39:03