Django使用Weasyprint生成PDF返回FileResponse显示数字序列如何解决
问题原因
- Weasyprint的
write_pdf()方法返回的是二进制字节流(bytes),而Django的FileResponse要求传入的参数是类文件对象(支持read()方法的对象),而非直接的bytes数据 - 当你直接把bytes传给FileResponse时,Django会将bytes按单字节迭代,每个字节会被转为对应的十进制数字输出到页面,就是你看到的长串数字。你另一个直接下载原始文件的视图正常,就是因为文件对象本身就是符合要求的类文件对象。
修复方案
方案1(推荐):用BytesIO包装字节流适配FileResponse
把生成的PDF字节流包装为io.BytesIO类文件对象再传给FileResponse即可,修改后的代码如下:
import io from django.http import FileResponse from django.shortcuts import get_object_or_404 from weasyprint import HTML, CSS def download_pdf(request, song_id): song = get_object_or_404(Song, pk=song_id) song.chordsheet.open("r") chordsheet_html = HTML(string=chopro2html(song.chordsheet.read())) chordsheet_css = CSS(string="div.chords-lyrics-line {display: flex; font-family: Roboto Mono, monospace;}") song.chordsheet.close() # 核心修改:把pdf字节流包装为BytesIO类文件对象 pdf_file = io.BytesIO(chordsheet_html.write_pdf(stylesheets=[chordsheet_css])) return FileResponse(pdf_file, as_attachment=True, filename=f"{song.title}_{song.artist}.pdf")
方案2:改用HttpResponse直接返回字节流
不需要额外包装字节流,直接设置响应头即可:
from django.http import HttpResponse from django.shortcuts import get_object_or_404 from weasyprint import HTML, CSS def download_pdf(request, song_id): song = get_object_or_404(Song, pk=song_id) song.chordsheet.open("r") chordsheet_html = HTML(string=chopro2html(song.chordsheet.read())) chordsheet_css = CSS(string="div.chords-lyrics-line {display: flex; font-family: Roboto Mono, monospace;}") song.chordsheet.close() pdf_content = chordsheet_html.write_pdf(stylesheets=[chordsheet_css]) response = HttpResponse(pdf_content, content_type="application/pdf") response["Content-Disposition"] = f"attachment; filename={song.title}_{song.artist}.pdf" return response
如果文件名包含中文,可以使用Django的urlquote工具处理文件名避免乱码。
内容的提问来源于stack exchange,提问作者AAM111
相关产品推荐
相关产品推荐

