我正在使用一个View,用户可以在其中上传csv文件。但是,根据过去的经验,我们知道这些用户上传的.csv
文件的列名通常包含多余的空格,大写字母或较小的拼写错误,导致其余代码跳闸
(例如:[Username, E-mail, lastname']
代替['username', 'email', 'lastname']
)
这些文件是使用ModelForm
上传的,它们被附加到FileField
模型的StudentImport
。
我想出了一个解决方案,其中我将使用clean_import_file
方法检查标题,如果标题与预期的标题不匹配,请对其进行编辑。代码的那部分工作正常,但是在最后一步遇到了麻烦:用新编辑的文件覆盖原始(有缺陷的)文件。
class StudentImportForm(forms.ModelForm):
class Meta:
model = models.StudentImport
fields = ['import_file']
def save(self, commit=True):
obj = super(StudentImportForm, self).save(commit=False)
obj.created_by = self.created_by
obj.file_type = self.file_type
if commit:
obj.save()
return obj
def clean_import_file(self):
file = self.cleaned_data['import_file']
df = pd.read_csv(
pd.compat.StringIO(file.read())
)
file.seek(0)
if list(df.columns) != EXPECTED_COLUMNS:
og_columns = list(df.columns.copy())
# Try minor fixes and see if this is enough
df.columns = [x.lower() for x in df.columns]
df.columns = [x.strip() for x in df.columns]
df.columns = ['email' if 'mail' in x else x for x in df.columns]
# Check if this is enough
if list(df.columns) != EXPECTED_COLUMNS:
raise forms.ValidationError(
'Column mismatch! Expected: {}, '
'received: {}'.format(EXPECTED_COLUMNS, og_columns)
)
file = StringIO()
df.to_csv(file)
return file
当我上传一个(有缺陷但可修复的).csv
文件时,我遇到了
AttributeError: StringIO instance has no attribute '_committed'
错误。
由于StringIO
对象似乎缺少必需的参数,我希望基于ContentFile
的方法可以解决该问题,
file = ContentFile(df.to_csv)
self.cleaned_data['import_file'] = file
return file
此代码本身并未引发任何错误,但是由于该表单现在抱怨import_file
字段为空,因此未能上传有效文件。
我过去曾使用StringIO
对象链接到Django模型,所以我尚不完全清楚为什么这种方法现在会失败。有人知道我在做什么错吗?