excel Django上传和处理多个文件失败

ymdaylpp  于 2023-02-20  发布在  Go
关注(0)|答案(1)|浏览(140)

我正在开发一个可以处理excel文件的Django应用程序。它只能处理xlsx文件,但如果你上传xlsods文件,我会先将其转换为xlsx,以便处理该文件。我的应用程序支持表单中的多个文件上传。所有上传的文件都上传成功,并保存到数据库中的模型中,字段为status = 'Created'。后保存模型函数触发一个新的处理文件的线程,以便在后台处理这些文件。处理完文件后,它们会另存为status = 'Error'status = 'Processed'。我还添加了一个额外的选项来重新处理文件。
当我尝试上传多个不是xlsx的文件时,这些文件需要在我自己处理之前转换成xlsx。为此,我在python子进程中使用libreoffice --convert-to xlsx filename --headless。这在同时上传一个或两个文件时工作正常。但如果我同时上传多个文件,有些文件处理失败,有些文件处理成功,而且文件中没有任何模式。如果我逐个上传所有测试文件,或者即使我重新处理这些文件,所有测试文件都能正常工作。
这个错误是由libreoffice给出的,因为如果我上传了多个已经是xlsx的文件,文件也会被成功处理。当这种情况发生时,libreoffice返回1,没有stdout也没有stderr。

    • 型号. py**
class Document(models.Model):
    docfile = models.FileField(upload_to='documents/%Y/%m/%d')
    date_creation = models.DateTimeField(auto_now_add=True)
    document_type = models.TextField(max_length=256)
    status = models.TextField(max_length=256, default="Created")
    bank_account = models.TextField(max_length=256, null=True)

    def filename(self):
        return os.path.basename(self.docfile.name)

@receiver(models.signals.post_save, sender=Document)
def process_file(sender, instance, **kwargs):
    t = threading.Thread(target=process_file_function,args=[sender,instance],daemon=True)
    t.start()
    • 函数. py**
def process_file_function(sender, instance, **kwargs):
    from accounting.models import Asiento, Apunte, FiltroBanco
    import pytz

    if instance.status == "Created" or instance.status == "Reprocess":
        filename = file = instance.docfile.name
        instance.status='Processing'
        instance.save(update_fields=['status'])

        print(f"Starting processing file: {file}")

        try:
            if filename.endswith('.ods') or filename.endswith('xls'):
                import os
                print(os.stat(filename))
                output = subprocess.run(["libreoffice", "--convert-to", "xlsx", filename, "--headless", "--outdir", "/tmp/sage/"], capture_output=True)
                print(output)
                filename = f"/tmp/sage/{filename.split('/')[-1].replace('xls', 'xlsx').replace('.ods', '.xlsx')}"

            wb = load_workbook(filename=filename, data_only=True)

            # Do my stuff

            instance.status='Processed'
            instance.save()
            print(f"Finished processing file: {file}")
        except Exception as e:
            instance.status='Error'
            instance.save()

成功文件的Otuput示例:

Starting processing file: documents/2023/02/19/filename02.ods
os.stat_result(st_mode=33188, st_ino=901900, st_dev=40, st_nlink=1, st_uid=1000, st_gid=1000, st_size=29771, st_atime=1676805630, st_mtime=1676805630, st_ctime=1676805630)
CompletedProcess(args=['libreoffice', '--convert-to', 'xlsx', 'documents/2023/02/19/filename02.ods', '--headless', '--outdir', '/tmp/sage/'], returncode=0, stdout=b'convert /home/ajulian/Documents/code/python/facturasweb/documents/2023/02/19/filename02.ods -> /tmp/sage/filename02.xlsx using filter : Calc Office Open XML\n', stderr=b'')
Finished processing file: documents/2023/02/19/filename02.ods

错误文件的输出示例:

Starting processing file: documents/2023/02/19/filename01.ods
os.stat_result(st_mode=33188, st_ino=901899, st_dev=40, st_nlink=1, st_uid=1000, st_gid=1000, st_size=21469, st_atime=1676805630, st_mtime=1676805630, st_ctime=1676805630)
CompletedProcess(args=['libreoffice', '--convert-to', 'xlsx', 'documents/2023/02/19/filename01.ods', '--headless', '--outdir', '/tmp/sage/'], returncode=1, stdout=b'', stderr=b'')
ERROR: Error processing file: documents/2023/02/19/filename01.ods
-----
Traceback (most recent call last):
  File "/home/ajulian/Documents/code/python/facturasweb/accounting/functions.py", line 50, in process_file_function
    wb = load_workbook(filename=filename, data_only=True)
  File "/usr/local/lib/python3.9/dist-packages/openpyxl/reader/excel.py", line 315, in load_workbook
    reader = ExcelReader(filename, read_only, keep_vba,
  File "/usr/local/lib/python3.9/dist-packages/openpyxl/reader/excel.py", line 124, in __init__
    self.archive = _validate_archive(fn)
  File "/usr/local/lib/python3.9/dist-packages/openpyxl/reader/excel.py", line 96, in _validate_archive
    archive = ZipFile(filename, 'r')
  File "/usr/lib/python3.9/zipfile.py", line 1239, in __init__
    self.fp = io.open(file, filemode)
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/sage/filename01.xlsx'

注意libreoffice子进程输出的不同,不要责怪filename01.ods,因为这个文件在其他执行中转换成功了,它只发生在多个文件上传时,而不是所有文件。
可能是什么问题?为什么有时会发生这种情况,有时不会?为什么libreoffice只返回1而没有任何输出?
先谢了。

q3qa4bjr

q3qa4bjr1#

解决了这个问题。当libreoffice试图同时打开相同的用户配置时会发生这个问题。通过为每个文件创建一个新的用户空间来解决:"-env:UserInstallation=file://{tmpfile}"

tmpfile = f"/tmp/sage/sessions/{filename.split('/')[-1].split('.')[0]}"
subprocess.run(["libreoffice", "--convert-to", "xlsx", filename, "--headless", "--outdir", "/tmp/sage/", f"-env:UserInstallation=file://{tmpfile}"], capture_output=True)

相关问题