在 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_typeuploaded_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)
    ...