3分钟上手!WeasyPrint与Python Web框架集成:Django/Flask PDF生成方案

3分钟上手!WeasyPrint与Python Web框架集成:Django/Flask PDF生成方案

【免费下载链接】WeasyPrint The awesome document factory 【免费下载链接】WeasyPrint 项目地址: https://gitcode.com/gh_mirrors/we/WeasyPrint

你是否还在为Python Web应用生成PDF文件烦恼?从发票、报告到用户证书,动态PDF生成是许多业务系统的刚需功能。但现有方案要么依赖复杂的LaTeX模板,要么受制于浏览器渲染的兼容性问题。本文将展示如何用WeasyPrint与Django/Flask无缝集成,3行代码实现专业级PDF文档生成。

读完本文你将掌握:

  • Django视图中直接输出PDF响应的2种实现方式
  • Flask路由中生成可下载PDF的最佳实践
  • 自定义页眉页脚和分页控制的CSS技巧
  • 生产环境中的性能优化与缓存策略

核心原理:HTML+CSS=PDF的现代方案

WeasyPrint作为Python生态中最成熟的PDF生成工具,其核心优势在于将Web标准(HTML/CSS)转化为高质量PDF。不同于传统PDF库需要手动绘制内容,WeasyPrint允许开发者使用熟悉的前端技术定义文档结构,通过HTML.write_pdf()方法一键转换。

这种"所见即所得"的开发模式带来三大好处:

  1. 开发效率:复用前端工程师和现有CSS框架
  2. 设计灵活:利用CSS Paged Media实现复杂排版
  3. 维护成本:模板与业务逻辑分离,便于修改

Django集成:从模板到PDF响应

Django与WeasyPrint的集成遵循MVT架构,典型场景是在视图层将渲染好的模板转换为PDF。以下是两种生产级实现方案:

基础方案:直接生成PDF响应

from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML  # 导入核心类[weasyprint/__init__.py#L116]

def invoice_pdf(request, invoice_id):
    invoice = Invoice.objects.get(id=invoice_id)
    html = render_to_string('invoices/invoice.html', {'invoice': invoice})
    
    # 核心转换代码:HTML字符串 → PDF字节流
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = f'attachment; filename="invoice_{invoice_id}.pdf"'
    
    HTML(string=html).write_pdf(response)  # 关键调用[weasyprint/__init__.py#L267]
    return response

高级方案:带权限控制的PDF视图

对于需要用户认证的敏感文档,建议使用Django的权限系统结合WeasyPrint的缓存机制:

from django.contrib.auth.decorators import login_required
from weasyprint import HTML, Attachment  # 支持文件附件[weasyprint/__init__.py#L319]

@login_required
def secure_report(request):
    # 权限验证
    if not request.user.has_perm('reports.view_secure'):
        return HttpResponseForbidden()
        
    # 优化:使用缓存减少重复渲染[docs/common_use_cases.rst#L490]
    cache_key = f"report_{request.user.id}"
    cached_pdf = cache.get(cache_key)
    
    if not cached_pdf:
        html = render_to_string('reports/secure.html', {'user': request.user})
        # 添加数字签名附件
        attachments = [Attachment(string=request.user.signature, name='signature.png')]
        # 生成PDF/A-3a归档格式[docs/common_use_cases.rst#L108]
        pdf = HTML(string=html).write_pdf(pdf_variant='pdf/a-3a', attachments=attachments)
        cache.set(cache_key, pdf, 3600)  # 缓存1小时
        
    response = HttpResponse(cached_pdf, content_type='application/pdf')
    response['Content-Disposition'] = 'inline; filename="secure_report.pdf"'
    return response

Flask集成:轻量级路由中的PDF生成

Flask的轻量级特性与WeasyPrint的简洁API相得益彰,特别适合中小型应用。以下是两种常用模式:

路由直接输出

from flask import Flask, render_template_string
from weasyprint import HTML  # 核心依赖[weasyprint/__init__.py]

app = Flask(__name__)

@app.route('/resume/<username>')
def generate_resume(username):
    user = get_user_profile(username)
    
    # 内联模板示例
    html_template = '''
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            @page { size: A4; margin: 2cm }  /* 页面设置[docs/common_use_cases.rst#L88] */
            .header { position: fixed; top: 0; right: 0 }
        </style>
    </head>
    <body>
        <div class="header">文档</div>
        <h1>{{ user.name }}的简历</h1>
        <!-- 内容 -->
    </body>
    </html>
    '''
    
    html = render_template_string(html_template, user=user)
    return HttpResponse(
        HTML(string=html).write_pdf(),
        content_type='application/pdf',
        headers={'Content-Disposition': f'attachment; filename="{username}_resume.pdf"'}
    )

使用蓝图组织PDF相关路由

对于大型Flask应用,建议使用蓝图集中管理PDF生成功能:

from flask import Blueprint, request, make_response
from weasyprint import HTML, CSS  # CSS类[weasyprint/__init__.py#L272]

pdf_bp = Blueprint('pdf', __name__, url_prefix='/pdf')

@pdf_bp.route('/receipt', methods=['POST'])
def generate_receipt():
    data = request.json
    
    # 应用自定义样式表
    css = CSS(string='''
        .total { font-size: 18pt; color: #e63946; }
        @page { @bottom-center { content: "Page " counter(page) } }  /* 页码[docs/common_use_cases.rst#L99] */
    ''')
    
    html = f'''
    <html>
        <head><title>Receipt #{data['id']}</title></head>
        <body>
            <h1>Payment Receipt</h1>
            <p>Amount: ${data['amount']}</p>
            <p class="total">Total: ${data['amount']}</p>
        </body>
    </html>
    '''
    
    # 生成PDF并设置缓存控制头
    response = make_response(HTML(string=html).write_pdf(stylesheets=[css]))
    response.headers['Content-Type'] = 'application/pdf'
    response.headers['Cache-Control'] = 'public, max-age=86400'  # 缓存1天
    return response

高级排版控制:CSS技巧与最佳实践

专业PDF通常需要精确的排版控制,WeasyPrint完全支持CSS Paged Media标准,通过docs/common_use_cases.rst#adjust-document-dimensions可实现复杂布局:

自定义页面大小与边距

@page {
    size: A5 landscape;  /* 横向A5纸张 */
    margin: 2cm;
    
    /* 页眉页脚 */
    @top-center { 
        content: "文档";
        font-size: 10pt;
        color: #666;
    }
    @bottom-right {
        content: "Page " counter(page) " of " counter(pages);
    }
}

处理分页与表格断裂

/* 避免标题孤行 */
h2 { 
    page-break-after: avoid;
    page-break-inside: avoid;
}

/* 表格跨页显示优化 */
table {
    page-break-inside: auto;
}
tr {
    page-break-inside: avoid;
    page-break-after: auto;
}

性能优化:生产环境注意事项

在高并发场景下,建议实施以下优化策略(docs/common_use_cases.rst#improve-rendering-speed-and-memory-use):

  1. 图片优化:启用图片压缩与缓存
HTML(string=html).write_pdf(
    optimize_images=True,  # 自动优化图片
    jpeg_quality=75,       # JPEG质量控制
    dpi=150,               # 降低分辨率
    cache=image_cache      # 共享缓存对象
)
  1. 异步生成:对大型文档使用Celery异步处理
@shared_task
def generate_large_report(user_id, report_id):
    # 长时间运行的PDF生成任务
    html = render_to_string('large_report.html', {'user_id': user_id})
    pdf = HTML(string=html).write_pdf()
    Report.objects.filter(id=report_id).update(pdf_file=pdf)
  1. 资源复用:共享字体配置与CSS解析结果
from weasyprint.text.fonts import FontConfiguration

# 全局字体配置单例
font_config = FontConfiguration()

def generate_pdf(html):
    return HTML(string=html).write_pdf(font_config=font_config)

总结与后续展望

WeasyPrint通过将Web技术栈转化为PDF生成能力,大幅降低了Python后端的文档生成门槛。无论是Django的企业级应用还是Flask的轻量级服务,都能通过简洁API实现专业文档输出。

官方文档docs/common_use_cases.rst还提供了更多高级场景:

  • PDF/UA无障碍标准支持
  • Factur-X/ZUGFeRD电子发票生成
  • 动态表单与文件附件功能

建议收藏本文并关注项目更新,下一篇我们将深入探讨复杂报表的自动化测试与CI/CD集成方案。

【免费下载链接】WeasyPrint The awesome document factory 【免费下载链接】WeasyPrint 项目地址: https://gitcode.com/gh_mirrors/we/WeasyPrint

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值