在 Django 中迭代并验证上传的大型 CSV 文件
Iterate over and validate large uploaded CSV files in Django
我正在使用 Django 模块 django-chunked-upload 接收可能较大的 CSV 文件。我可以假设 CSV 格式正确,但我不能假设分隔符是什么。
上传完成后,返回一个UploadedFile object。我需要验证上传的 CSV 中是否包含正确的列,以及每列中的数据类型是否正确。
使用 csv.reader()
加载文件不起作用:
reader = csv.reader(uploaded_file)
next(reader)
>>> _csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)
这可能是因为 uploaded_file.content_type
和 uploaded_file.charset
都是 None
。
我想出了一个相当不优雅的解决方案来获取 header 并遍历行:
i = 0
header = ""
for line in uploaded_file:
if i == 0:
header = line.decode('utf-8')
header_list = list(csv.reader(StringIO(header)))
print(header_list[0])
#validate column names
else:
tiny_csv = StringIO(header + line.decode('utf-8'))
reader = csv.DictReader(tiny_csv)
print(next(reader))
#validate column types
我也考虑过尝试加载实际保存文件的路径:
path = #figure out the path of the temp file
f = open(path,"r")
reader = csv.reader(f)
但是我无法从 UploadedFile 中获取临时文件路径 object。
理想情况下,我想从 UploadedFile object 创建一个普通的 reader 或 DictReader,但它似乎让我望而却步。有人有主意吗? - 谢谢
答案在 chunked_upload/models.py 中,其中包含以下行:
def get_uploaded_file(self):
self.file.close()
self.file.open(mode='rb') # mode = read+binary
return UploadedFile(file=self.file, name=self.filename,
size=self.offset)
因此,当您创建文件模型时,您可以选择使用 mode='r'
打开文件:
#myapp/models.py
from django.db import models
from chunked_upload.models import ChunkedUpload
from django.core.files.uploadedfile import UploadedFile
class FileUpload(ChunkedUpload):
def get_uploaded_file(self):
self.file.close()
self.file.open(mode='r') # mode = read+binary
return UploadedFile(file=self.file, name=self.filename,
size=self.offset)
这允许您获取返回的 UploadedFile 实例并将其解析为 csv:
def on_completion(self, uploaded_file, request):
reader = csv.reader(uploaded_file)
...
我正在使用 Django 模块 django-chunked-upload 接收可能较大的 CSV 文件。我可以假设 CSV 格式正确,但我不能假设分隔符是什么。
上传完成后,返回一个UploadedFile object。我需要验证上传的 CSV 中是否包含正确的列,以及每列中的数据类型是否正确。
使用 csv.reader()
加载文件不起作用:
reader = csv.reader(uploaded_file)
next(reader)
>>> _csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)
这可能是因为 uploaded_file.content_type
和 uploaded_file.charset
都是 None
。
我想出了一个相当不优雅的解决方案来获取 header 并遍历行:
i = 0
header = ""
for line in uploaded_file:
if i == 0:
header = line.decode('utf-8')
header_list = list(csv.reader(StringIO(header)))
print(header_list[0])
#validate column names
else:
tiny_csv = StringIO(header + line.decode('utf-8'))
reader = csv.DictReader(tiny_csv)
print(next(reader))
#validate column types
我也考虑过尝试加载实际保存文件的路径:
path = #figure out the path of the temp file
f = open(path,"r")
reader = csv.reader(f)
但是我无法从 UploadedFile 中获取临时文件路径 object。
理想情况下,我想从 UploadedFile object 创建一个普通的 reader 或 DictReader,但它似乎让我望而却步。有人有主意吗? - 谢谢
答案在 chunked_upload/models.py 中,其中包含以下行:
def get_uploaded_file(self):
self.file.close()
self.file.open(mode='rb') # mode = read+binary
return UploadedFile(file=self.file, name=self.filename,
size=self.offset)
因此,当您创建文件模型时,您可以选择使用 mode='r'
打开文件:
#myapp/models.py
from django.db import models
from chunked_upload.models import ChunkedUpload
from django.core.files.uploadedfile import UploadedFile
class FileUpload(ChunkedUpload):
def get_uploaded_file(self):
self.file.close()
self.file.open(mode='r') # mode = read+binary
return UploadedFile(file=self.file, name=self.filename,
size=self.offset)
这允许您获取返回的 UploadedFile 实例并将其解析为 csv:
def on_completion(self, uploaded_file, request):
reader = csv.reader(uploaded_file)
...