Django表单上传文件报‘bad filename’,设置内存阈值后异常
问题描述
在Django项目中使用PyMuPDF生成PDF预览图的代码原本运行正常,但将DATA_UPLOAD_MAX_MEMORY_SIZE和FILE_UPLOAD_MAX_MEMORY_SIZE设置为500MB后,出现bad filename错误。
- 未设置阈值时,
self.request.FILES['book_file'].file是tempfile._TemporaryFileWrapper对象 - 设置阈值后,该对象变为
_io.BytesIO对象
相关代码:
def form_valid(self, form): text_book = form.save(commit=False) text_book.owner_id = self.request.user.pk # i'm trying to get the first page to make preview image my_file = self.request.FILES['book_file'].file pdf_file = fitz.open(my_file) page = pdf_file.load_page(0) pix = page.get_pixmap() preview_image = Image.frombytes('RGB', [pix.width, pix.height], pix.samples) preview_image.thumbnail((200, 200)) image_io = BytesIO() preview_image.save(image_io, format='JPEG') image_data = image_io.getvalue() content_file = ContentFile(image_data) text_book.preview_image.save(f'text_book_preview_image{Path(text_book.book_file.name).stem}_preview.jpg', content_file, save=False) text_book.save() return HttpResponseRedirect(self.success_url)
设置的配置:
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 500 FILE_UPLOAD_MAX_MEMORY_SIZE = DATA_UPLOAD_MAX_MEMORY_SIZE
问题原因
Django的文件上传机制会根据FILE_UPLOAD_MAX_MEMORY_SIZE判断文件存储方式:
- 当文件大小小于阈值时,文件会直接保存在内存中,对应
BytesIO对象 - 当文件大小大于阈值时,会生成临时文件,对应
tempfile._TemporaryFileWrapper对象
PyMuPDF的fitz.open()方法默认会通过文件名后缀判断文件类型,但BytesIO对象没有真实的文件名,无法自动识别PDF格式,因此抛出bad filename错误。
解决方案
修改fitz.open()的调用方式,手动指定文件类型为pdf,让PyMuPDF无需通过文件名识别格式:
def form_valid(self, form): text_book = form.save(commit=False) text_book.owner_id = self.request.user.pk # 获取上传的文件对象 book_file = self.request.FILES['book_file'] # 手动指定filetype为'pdf',兼容内存中的BytesIO和临时文件 pdf_file = fitz.open(stream=book_file.read(), filetype='pdf') page = pdf_file.load_page(0) pix = page.get_pixmap() preview_image = Image.frombytes('RGB', [pix.width, pix.height], pix.samples) preview_image.thumbnail((200, 200)) image_io = BytesIO() preview_image.save(image_io, format='JPEG') image_data = image_io.getvalue() content_file = ContentFile(image_data) text_book.preview_image.save(f'text_book_preview_image{Path(book_file.name).stem}_preview.jpg', content_file, save=False) text_book.save() return HttpResponseRedirect(self.success_url)
内容的提问来源于stack exchange,提问作者Anna_Silchenko
相关产品推荐
相关产品推荐

