如何一次性创建包含多列的CSV数据Schema模型?
解决Django中Schema与关联Column的批量创建及表单实现问题
一、模型参考定义
假设你的模型结构如下(如果已有定义可跳过此部分):
from django.db import models class Schema(models.Model): name = models.CharField(max_length=255) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name class Column(models.Model): SCHEMA_FIELD_TYPES = ( ('string', '字符串'), ('integer', '整数'), ('date', '日期'), ) schema = models.ForeignKey(Schema, on_delete=models.CASCADE, related_name='columns') name = models.CharField(max_length=255) # CSV表头名称 field_type = models.CharField(max_length=50, choices=SCHEMA_FIELD_TYPES) order = models.IntegerField(default=0) # 排序序号 class Meta: ordering = ['order'] def __str__(self): return f"{self.schema.name} - {self.name}"
二、一次性创建Schema及其关联列
事务+批量创建方案
用Django事务保证原子性,避免出现Schema创建成功但列创建失败的不一致情况:
from django.db import transaction def create_schema_with_columns(schema_name, columns_data): # columns_data格式示例: # [ # {'name': '用户名', 'field_type': 'string', 'order': 1}, # {'name': '年龄', 'field_type': 'integer', 'order': 2}, # {'name': '注册日期', 'field_type': 'date', 'order': 3} # ] with transaction.atomic(): schema = Schema.objects.create(name=schema_name) # 构造Column对象列表 column_objs = [ Column( schema=schema, name=col['name'], field_type=col['field_type'], order=col['order'] ) for col in columns_data ] # 批量插入提升效率 Column.objects.bulk_create(column_objs) return schema
调用示例:
columns = [ {'name': '商品名称', 'field_type': 'string', 'order': 1}, {'name': '价格', 'field_type': 'integer', 'order': 2} ] create_schema_with_columns('商品信息', columns)
三、实现动态添加列的表单
使用Django表单集(FormSet)支持任意数量的列添加:
1. 定义表单及表单集
from django import forms class ColumnForm(forms.ModelForm): class Meta: model = Column fields = ['name', 'field_type', 'order'] widgets = { 'order': forms.NumberInput(attrs={'min': 0}), } # 创建关联Schema的内联表单集 ColumnFormSet = forms.inlineformset_factory( Schema, Column, form=ColumnForm, extra=1, # 默认显示1个空列表单 can_delete=True, # 允许删除已添加的列 can_order=False # 用自定义order字段,关闭表单集自带排序 )
2. 视图处理逻辑
from django.shortcuts import render, redirect def schema_create(request): if request.method == 'POST': # 处理Schema名称表单 schema_form = forms.ModelForm(model=Schema, fields=['name'])(request.POST) # 处理列表单集 formset = ColumnFormSet(request.POST, instance=Schema()) if schema_form.is_valid() and formset.is_valid(): # 先保存Schema实例 schema = schema_form.save() # 将表单集关联到Schema并保存所有列 formset.instance = schema formset.save() return redirect('schema_list') # 替换为你的Schema列表页路由 else: schema_form = forms.ModelForm(model=Schema, fields=['name'])() formset = ColumnFormSet(instance=Schema()) return render(request, 'schema_create.html', { 'schema_form': schema_form, 'formset': formset })
3. 模板实现(schema_create.html)
添加JS支持动态添加列表单:
<form method="post"> {% csrf_token %} <div class="schema-section"> <h3>Schema名称</h3> {{ schema_form.as_p }} </div> <div class="columns-section"> <h3>列配置</h3> {{ formset.management_form }} {% for form in formset %} <div class="column-form"> {{ form.as_p }} {% if form.instance.pk %} {{ form.DELETE }} <label for="{{ form.DELETE.id_for_label }}">删除此列</label> {% endif %} </div> {% endfor %} <button type="button" id="add-column-btn">添加新列</button> </div> <button type="submit" class="save-btn">保存Schema</button> </form> <script> document.getElementById('add-column-btn').addEventListener('click', function() { const columnForms = document.querySelectorAll('.column-form'); const lastForm = columnForms[columnForms.length - 1]; const newForm = lastForm.cloneNode(true); // 更新表单集计数 const totalFormsInput = document.getElementById('id_columns-TOTAL_FORMS'); const currentFormNum = parseInt(totalFormsInput.value); totalFormsInput.value = currentFormNum + 1; // 更新表单字段的name和id属性,适配Django表单集规则 newForm.innerHTML = newForm.innerHTML.replace(/columns-\d+/g, `columns-${currentFormNum}`); // 清空新表单的输入值 newForm.querySelectorAll('input, select').forEach(input => { input.value = ''; if (input.type === 'checkbox') input.checked = false; }); lastForm.parentNode.appendChild(newForm); }); </script>
四、关键注意事项
- 事务原子性:必须用
transaction.atomic()包裹创建逻辑,防止部分数据写入失败。 - 表单集规则:动态添加表单时必须更新
TOTAL_FORMS计数和字段命名,否则Django无法解析表单数据。 - 排序逻辑:Column模型的
Meta.ordering配置确保查询时按order字段排序,生成CSV时直接遍历schema.columns.all()即可得到有序列。
内容的提问来源于stack exchange,提问作者qioto
相关产品推荐
相关产品推荐

