Django中如何将上传CSV文件的行数据自动保存至Dataset数据库模型
解决Django中CSV数据自动存入Dataset模型的问题
咱们一步步来调整你的代码,实现把CSV第一行存到user_A字段、第二行存到user_B字段的需求:
核心思路
- 先确保
FileForm验证通过并保存File实例(因为Dataset需要关联这个实例) - 正确提取CSV中的两行数据,转换为方便取值的格式
- 基于保存的
File实例和CSV数据,创建并保存Dataset对象 - 修正视图中变量未定义的潜在问题
修改后的Views代码
from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required import pandas as pd from .models import File, Dataset from .forms import FileForm @login_required def file_upload(request): data = None first_row = None second_row = None message = "" # 初始化message变量,避免未定义报错 if request.method == 'POST': file_form = FileForm(request.POST, request.FILES) # 这里只验证FileForm即可,Dataset是自动填充的,不需要用户提交DataForm if file_form.is_valid(): uploaded_file = request.FILES['file_upload'] try: # 读取CSV数据 data = pd.read_csv(uploaded_file, header=0, encoding="UTF-8") # 检查CSV至少包含两行有效数据 if len(data) < 2: message = "CSV文件至少需要包含两行数据" context = {'file_form': file_form, 'message': message} return render(request, 'upload_file.html', context) # 提取第一行和第二行数据(用iloc[0]返回Series,更方便取值) first_row = data.iloc[0] second_row = data.iloc[1] # 保存File实例 file_instance = file_form.save(commit=False) file_instance.user = request.user.profile file_instance.filename = uploaded_file.name file_instance.save() # 创建并保存Dataset实例 dataset = Dataset() dataset.user = request.user.profile dataset.file_uploaded = file_instance # 关联已保存的File对象 # 映射CSV第一行到user_A字段(注意列名要和CSV表头完全一致!) # 假设你的CSV表头是name, code, tot, sd,根据实际情况调整 dataset.name_user_A = first_row['name'] # 重要提醒:如果CSV中的code是字符串(比如aa/bb),需把Dataset的code_user_A改成CharField! dataset.code_user_A = first_row['code'] dataset.total_user_A = first_row['tot'] dataset.sd_user_A = first_row['sd'] # 映射CSV第二行到user_B字段 dataset.name_user_B = second_row['name'] dataset.code_user_B = second_row['code'] dataset.total_user_B = second_row['tot'] dataset.sd_user_B = second_row['sd'] dataset.save() message = "文件上传和数据保存成功!" return redirect('upload_file') except Exception as e: message = f"处理CSV时出错:{str(e)}" context = {'file_form': file_form, 'message': message} return render(request, 'upload_file.html', context) else: message = "表单验证失败,请检查输入" context = {'file_form': file_form, 'message': message} return render(request, 'upload_file.html', context) else: # GET请求时初始化空表单 file_form = FileForm() # 准备上下文变量,确保所有变量都已定义 context = { 'data': data, 'second_row': second_row, 'file_form': file_form, 'message': message, } return render(request, 'upload_file.html', context)
关键细节说明
表单逻辑调整:
- 移除了
data_form的验证逻辑,因为Dataset是自动填充的,不需要用户提交该表单,直接通过代码创建即可 - 增加了异常捕获,处理CSV读取失败、数据行数不足等异常情况
- 移除了
CSV数据提取优化:
- 用
data.iloc[0]代替data.iloc[[0]],返回Series对象后可以直接通过列名取值,更简洁 - 增加了CSV行数检查,避免因数据不足导致后续赋值报错
- 用
模型字段匹配注意:
- 你的
Dataset模型中code_user_A是PositiveIntegerField,但CSV中的code是字符串(aa/bb),这会导致保存失败!你需要把模型中的code_user_A和code_user_B改成CharField(max_length=250),或者确保CSV中的code是整数格式
- 你的
上下文变量初始化:
- 在视图开头初始化了
first_row、second_row、message等变量,避免GET请求时出现变量未定义的报错
- 在视图开头初始化了
额外提示
- 如果你的CSV表头和代码中假设的(
name,code,tot,sd)不一致,一定要修改first_row['xxx']的键名,确保和CSV实际表头匹配 - 可以在模板中显示
message变量,让用户直观看到上传结果(成功/失败原因)
内容的提问来源于stack exchange,提问作者Pisa Ponente
相关产品推荐
相关产品推荐

