如何渲染多个HTML文件并与PDF一同打包为ZIP包提供下载
问题核心原因
原有代码的核心问题是没有正确获取模板渲染后的HTML内容,且ZIP文件的生成逻辑不符合Django流式响应的要求,之前报的Question对象没有"META"属性错误是因为错误将Question实例传入了需要request对象作为参数的渲染函数导致的。
修复后的完整实现代码
首先导入所需依赖:
import io import zipfile from django.template.loader import render_to_string from django.http import HttpResponse from weasyprint import HTML # 保留你原有导入的Question、Q等模块
视图函数实现:
def complete_order_zip_view(request, pk): zipfile_name = f'encomenda_{pk}.zip' # 直接将HttpResponse作为ZIP的写入对象,避免生成本地临时文件 response = HttpResponse(content_type='application/zip') response['Content-Disposition'] = f'attachment; filename={zipfile_name}' with zipfile.ZipFile(response, 'w', zipfile.ZIP_DEFLATED) as zip_file: # 1. 写入所有单题HTML文件 template_name = "single_question.html" questions = Question.objects.filter(Q(question_order=pk) & Q(revision_approval=True)) for idx, question in enumerate(questions, 1): # 用render_to_string直接获取渲染后的HTML字符串 html_content = render_to_string( template_name, # 传入模板所需的上下文参数 {"question": question}, request=request ) # 按序号命名文件写入ZIP zip_file.writestr(f'question_{idx}.html', html_content.encode('utf-8')) # 2. 写入3个PDF文件(替换为你自己的模板和渲染逻辑即可) # 2.1 订单详情PDF order_detail_html = render_to_string('order_detail.html', {"order_id": pk, "questions": questions}, request=request) order_detail_pdf = HTML(string=order_detail_html).write_pdf() zip_file.writestr(f'order_{pk}_detail.pdf', order_detail_pdf) # 2.2 第一版试卷格式PDF exam_paper1_html = render_to_string('exam_paper_v1.html', {"questions": questions}, request=request) exam_paper1_pdf = HTML(string=exam_paper1_html).write_pdf() zip_file.writestr(f'exam_paper_v1.pdf', exam_paper1_pdf) # 2.3 第二版试卷格式PDF exam_paper2_html = render_to_string('exam_paper_v2.html', {"questions": questions}, request=request) exam_paper2_pdf = HTML(string=exam_paper2_html).write_pdf() zip_file.writestr(f'exam_paper_v2.pdf', exam_paper2_pdf) return response
核心修改说明
- 用
render_to_string替代render:render返回的是HttpResponse对象,render_to_string会直接返回模板渲染后的纯文本内容,符合写入ZIP的需求,明确区分request和模板上下文参数即可解决META属性报错问题。 - 直接将HttpResponse作为ZIP的写入载体:不需要生成本地临时文件,既减少IO开销也避免多用户并发访问时的文件冲突问题。
- 使用
writestr方法写入内存内容:不管是HTML字符串还是WeasyPrint生成的PDF二进制内容,都可以直接用这个方法写入ZIP,不需要额外创建空的BytesIO缓存。
补充提示
如果渲染PDF时样式不生效,可以在WeasyPrint的HTML方法中传入base_url=request.build_absolute_uri('/')参数,确保静态资源路径可以被正确解析。
内容的提问来源于stack exchange,提问作者andrepz
相关产品推荐
相关产品推荐

