如何实现从HTML表单接收CSV文件并转换为JSON后存入Django模型?
当然有靠谱的实现方案!我帮你拆解成几个可落地的步骤,都是Django项目里常用的实践,完全贴合你的需求:
整体实现流程
核心逻辑是:HTML表单上传CSV → 后端读取CSV并转换为字典列表(JSON的Python原生形式,比先转JSON字符串更高效) → 批量校验并写入Django模型。
1. 构建HTML上传表单
首先需要一个支持文件上传的表单,注意必须设置enctype="multipart/form-data",还要带上Django的CSRF令牌:
<!-- templates/upload.html --> <form method="post" enctype="multipart/form-data"> {% csrf_token %} <div> <label>选择CSV文件:</label> <input type="file" name="csv_file" accept=".csv" required> </div> <button type="submit" style="margin-top:10px;">上传并导入数据</button> {% if error %} <p style="color:red;">{{ error }}</p> {% endif %} {% if success %} <p style="color:green;">{{ success }}</p> {% endif %} </form>
2. 后端处理CSV上传并转换为字典列表
这里提供两种实现方式,选你顺手的就行:
方式一:原生Python模块(无需额外依赖)
用Python内置的csv模块直接读取CSV,转成字典列表(直接可用于模型创建,无需额外JSON转换):
# views.py import csv from django.shortcuts import render from django.db import transaction from .models import YourModel # 替换成你的实际模型 def upload_csv(request): if request.method == 'POST': csv_file = request.FILES.get('csv_file') # 校验文件格式 if not csv_file.name.endswith('.csv'): return render(request, 'upload.html', {'error': '请上传正确的CSV格式文件'}) # 读取CSV内容并转成字典列表 try: # 解码文件内容并按行分割 csv_content = csv_file.read().decode('utf-8').splitlines() # 用DictReader将第一行作为键,每行数据转成字典 csv_reader = csv.DictReader(csv_content) data_list = list(csv_reader) except Exception as e: return render(request, 'upload.html', {'error': f'CSV解析失败:{str(e)}'}) # 写入模型(见步骤3) try: with transaction.atomic(): # 批量创建或循环创建,根据数据量选择 for item in data_list: # 注意:如果CSV列名和模型字段名不一致,需要手动映射 # 例如:YourModel.objects.create(name=item['商品名称'], price=item['售价']) YourModel.objects.create(**item) return render(request, 'upload.html', {'success': '数据导入成功!'}) except Exception as e: return render(request, 'upload.html', {'error': f'数据写入失败:{str(e)}'}) # GET请求时返回表单页面 return render(request, 'upload.html')
方式二:用Pandas简化操作(适合复杂CSV)
如果你的CSV有复杂格式(比如合并单元格、特殊编码),用Pandas会更省心,先安装依赖:pip install pandas
# views.py import pandas as pd from django.shortcuts import render from django.db import transaction from .models import YourModel def upload_csv(request): if request.method == 'POST': csv_file = request.FILES.get('csv_file') if not csv_file.name.endswith('.csv'): return render(request, 'upload.html', {'error': '请上传CSV格式文件'}) try: # 读取CSV并转成字典列表 df = pd.read_csv(csv_file) data_list = df.to_dict('records') # 每行转成一个字典 except Exception as e: return render(request, 'upload.html', {'error': f'CSV解析失败:{str(e)}'}) # 写入模型逻辑和上面一致 try: with transaction.atomic(): YourModel.objects.bulk_create([YourModel(**item) for item in data_list]) return render(request, 'upload.html', {'success': '批量导入成功!'}) except Exception as e: return render(request, 'upload.html', {'error': f'数据写入失败:{str(e)}'}) return render(request, 'upload.html')
3. 关键优化建议
- 事务保障:用
transaction.atomic()包裹写入逻辑,确保要么全成功要么全失败,避免部分数据导入的混乱情况。 - 数据校验:如果需要严格校验数据格式(比如价格必须是数字、日期格式正确),可以用Django的序列化器或表单来校验:
from rest_framework import serializers from .models import YourModel class YourModelSerializer(serializers.ModelSerializer): class Meta: model = YourModel fields = '__all__' # 在写入时替换循环: for item in data_list: serializer = YourModelSerializer(data=item) serializer.is_valid(raise_exception=True) serializer.save() - 批量创建优化:如果数据量很大(比如上千条),用
bulk_create比循环create快10倍以上,但注意bulk_create不会触发模型的save信号,如果你的模型有信号处理逻辑,需要手动处理。 - 文件大小限制:在
settings.py中设置DATA_UPLOAD_MAX_MEMORY_SIZE = 10*1024*1024(限制10MB),或者在view里直接判断csv_file.size。
内容的提问来源于stack exchange,提问作者Neph
相关产品推荐
相关产品推荐

