Django中如何将含数据库动态数据的HTML转换为可下载PDF
Django动态HTML转PDF无动态内容解决方案
你遇到的只有静态H1、无动态填充数据的问题,核心原因基本都是转PDF时跳过了Django的模板渲染步骤:要么直接读取模板物理源文件传给PDF生成器,文件里全是{% for %}这类未解析的模板标签,动态内容根本没被填充;要么使用的PDF生成库对HTML标签兼容性极差,无法识别列表类动态节点。
下面给你兼容性最高、最不容易出问题的实现方案:
方案1:pdfkit + wkhtmltopdf(推荐,对HTML/CSS兼容性最好)
第一步:安装依赖
- 先安装渲染核心wkhtmltopdf系统组件:Windows直接下载对应安装包,安装后把bin目录加入系统环境变量;Linux发行版直接用源安装即可,比如
apt install wkhtmltopdf - 安装Python对应包:
pip install pdfkit
第二步:修改视图函数
核心逻辑是先用Django内置的render_to_string把模板和动态数据渲染成完整的、填充完所有内容的HTML字符串,再把这个字符串传给PDF生成器,不要直接读模板源文件。
参考代码如下:
import pdfkit from django.http import HttpResponse from django.template.loader import render_to_string def contrato(request, id): # 取业务数据,和你原有逻辑一致 asociado_data = get_queryset(id) # 渲染模板得到带完整动态内容的HTML字符串 html_str = render_to_string('contrato/contrato.html', {'asociado': asociado_data}) # 配置wkhtmltopdf路径,Windows如果没加环境变量就写死本地路径,比如r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe' wk_config = pdfkit.configuration(wkhtmltopdf='替换成你的wkhtmltopdf可执行文件路径') # 生成PDF文件流 pdf_file = pdfkit.from_string(html_str, False, configuration=wk_config) # 返回下载响应 response = HttpResponse(pdf_file, content_type='application/pdf') # 需要浏览器直接预览的话,把attachment改成inline response['Content-Disposition'] = 'attachment; filename="contrato_prestacion_servicios.pdf"' return response
方案2:WeasyPrint(无需额外装大型系统组件,纯Python实现)
如果不想装wkhtmltopdf,可以用WeasyPrint,核心逻辑和上面完全一致,必须先渲染得到完整HTML再转:
第一步:安装依赖
pip install weasyprint
第二步:视图代码参考
from django.http import HttpResponse from django.template.loader import render_to_string from weasyprint import HTML def contrato(request, id): asociado_data = get_queryset(id) html_str = render_to_string('contrato/contrato.html', {'asociado': asociado_data}) pdf_file = HTML(string=html_str).write_pdf() response = HttpResponse(pdf_file, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="contrato_prestacion_servicios.pdf"' return response
常见踩坑点
- 模板路径不要用Windows系统的反斜杠
\,统一写成正斜杠/,比如contrato/contrato.html,避免跨系统部署时找不到模板 - 模板里的CSS尽量写在页面内的
<style>标签里,或者用内联样式,不要引用外部静态CSS文件,否则PDF生成器读不到外部资源会丢样式 - 传模板上下文时和你原来用
render的参数保持完全一致即可,不需要额外做格式转换,queryset可以直接传给模板循环 - 如果你之前写的转码逻辑是直接
open('contrato/contrato.html').read()读文件,那100%会出动态内容丢失的问题,必须换成render_to_string完成渲染
内容的提问来源于stack exchange,提问作者Pepe Meza
相关产品推荐
相关产品推荐

