如何使用Django模板生成带有完整CSS样式的PDF文件?
Django模板生成带CSS样式的PDF解决方案
你当前用xhtml2pdf生成PDF时内容正常但CSS不生效,核心原因是xhtml2pdf对CSS的支持逻辑和浏览器不同,且外部资源加载存在局限,以下是具体解决步骤:
1. 优先使用内嵌CSS,避免外部样式文件
xhtml2pdf加载外部CSS文件容易出现路径解析问题,建议直接把CSS写在模板的<style>标签内,或给元素添加style属性。示例模板abc.html:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>PDF示例</title> <style type="text/css"> .page-container { width: 210mm; margin: 0 auto; padding: 15mm; } .header { color: #3498db; font-size: 22px; text-align: center; border-bottom: 2px solid #eee; padding-bottom: 10px; } .content-text { font-size: 14px; line-height: 1.8; margin-top: 20px; color: #333; } </style> </head> <body> <div class="page-container"> <h2 class="header">带样式的PDF标题</h2> <p class="content-text">这是应用了CSS样式的PDF内容,测试段落。</p> </div> </body> </html>
2. 修改PDF生成函数,添加资源回调
xhtml2pdf需要明确的资源路径才能加载静态文件(如字体、图片),给pisaDocument添加link_callback参数处理路径转换:
from io import BytesIO from xhtml2pdf import pisa from django.template.loader import get_template from django.http import HttpResponse from django.conf import settings import os def home(request): pdf = render_to_pdf("abc.html") return HttpResponse(pdf, content_type='application/pdf') def link_callback(uri, rel): # 处理静态文件和媒体文件路径 if uri.startswith(settings.STATIC_URL): path = os.path.join(settings.STATIC_ROOT, uri.replace(settings.STATIC_URL, "")) elif uri.startswith(settings.MEDIA_URL): path = os.path.join(settings.MEDIA_ROOT, uri.replace(settings.MEDIA_URL, "")) else: return uri # 外部资源直接返回原地址 # 校验文件是否存在 if not os.path.isfile(path): raise FileNotFoundError(f"静态资源未找到: {path}") return path def render_to_pdf(template_src, context_dict={}): template = get_template(template_src) html = template.render(context_dict) result = BytesIO() # 配置pisa文档,添加回调并改用UTF-8编码避免乱码 pdf = pisa.pisaDocument( BytesIO(html.encode("UTF-8")), result, link_callback=link_callback ) if not pdf.err: return HttpResponse(result.getvalue(), content_type='application/pdf') else: return None
3. 注意xhtml2pdf的CSS支持局限
xhtml2pdf基于ReportLab,对CSS的支持不如浏览器完善,需规避以下特性:
- 避免使用
float、flex等复杂布局,优先用<table>实现排版 - 伪类(如
:hover、:nth-child)、多层嵌套的后代选择器基本不支持 - 自定义字体需通过
@font-face引入,且要确保字体文件路径正确(配合上述link_callback)
4. 中文显示与字体配置
如果需要显示中文,需引入支持中文的字体(如宋体、微软雅黑),示例:
在静态目录static/fonts/下放入SimSun.ttf字体文件,然后在模板的<style>中添加:
@font-face { font-family: 'SimSun'; src: url('{% static "fonts/SimSun.ttf" %}') format('truetype'); } body { font-family: 'SimSun', serif; }
内容的提问来源于stack exchange,提问作者Ayushi Navthare
相关产品推荐
相关产品推荐

