You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何渲染多个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 02:06:02