我正在开发一个可以处理excel文件的Django应用程序。它只能处理xlsx
文件,但如果你上传xls
或ods
文件,我会先将其转换为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而没有任何输出?
先谢了。
1条答案
按热度按时间q3qa4bjr1#
解决了这个问题。当libreoffice试图同时打开相同的用户配置时会发生这个问题。通过为每个文件创建一个新的用户空间来解决:
"-env:UserInstallation=file://{tmpfile}"