Django生成PDF发票时如何嵌入动态SVG条形码?
Django渲染PDF时嵌入动态生成SVG条形码的解决方案
我之前也碰到过一模一样的问题——用Django+xhtml2pdf生成发票PDF,文本都正常显示,就是动态生成的SVG条形码死活出不来。试过直接传条形码对象、cid引用都没用,后来发现把SVG字节码转成base64编码的data URI嵌入HTML是最靠谱的办法,分享给你:
核心思路
xhtml2pdf对外部引用的SVG支持不太稳定,而且我们的SVG是动态生成的没存本地文件,cid引用还要处理附件逻辑特别麻烦。直接把SVG字节码转成base64编码的data URI,嵌入到HTML的img标签里,xhtml2pdf就能直接渲染出来,全程在内存里处理,不用存临时文件。
修改后的代码实现
1. 调整View中的条形码生成逻辑
把原来生成条形码对象的代码改成在内存中生成SVG字节码,再转成base64:
import base64 from io import BytesIO import barcode from barcode.writer import SVGWriter from django.views.generic import View class GenerateInvoicePdf(View): def get(self, request, *args, **kwargs): package = Package.objects.get(package_no=request.GET.get('package')) address = package.purchase.order_product.delivery_location # 1. 在内存中生成SVG条形码 CODE128 = barcode.get_barcode_class('code128') svg_buffer = BytesIO() # 使用SVGWriter直接写入内存缓冲区 barcode_obj = CODE128(package.package_no, writer=SVGWriter()) barcode_obj.write(svg_buffer) # 2. 转成base64编码并拼接成data URI svg_base64 = base64.b64encode(svg_buffer.getvalue()).decode('utf-8') barcode_data_uri = f'data:image/svg+xml;base64,{svg_base64}' if request.user.display_username == seller.display_username: data = { 'package': package, 'address': address, 'barcode_data_uri': barcode_data_uri, # 把这个传给模板 } pdf = render_to_pdf('pdf/invoice.html', data) if pdf: response = HttpResponse(pdf, content_type='application/pdf') filename = f"Invoice_{package.package_no}.pdf" content_disposition = "inline; filename='%s'" % filename if request.GET.get("download"): content_disposition = "attachment; filename='%s'" % filename response['Content-Disposition'] = content_disposition return response return HttpResponse("Not found")
2. 优化PDF渲染函数(可选)
把编码换成UTF-8,避免一些特殊字符的解析问题:
from io import BytesIO from django.http import HttpResponse from django.template.loader import get_template from xhtml2pdf import pisa def render_to_pdf(template_src, context_dict={}): template = get_template(template_src) html = template.render(context_dict) result = BytesIO() # 用UTF-8编码替代ISO-8859-1,适配更多字符场景 pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result) if not pdf.err: return HttpResponse(result.getvalue(), content_type='application/pdf') return None
3. 修改HTML模板
把原来的条形码对象引用换成img标签,直接使用生成的data URI:
<body> <div class="container-fluid"> <div class="row"> <div class="col-6"> <div class="row"> <div class="col-12"> <!-- 用data URI引用SVG条形码 --> <img src="{{ barcode_data_uri }}" alt="{{ package.package_no }}" style="height: 23mm; width: auto; display: block;" /> <br> {{ package.package_no }} <!-- 其他发票内容 --> </div> </div> </div> </div> </div> </body>
为什么这个方法能行?
- data URI把SVG的完整内容直接嵌入到HTML里,xhtml2pdf渲染时不需要读取外部文件,避免了文件路径、权限的问题
- base64编码把二进制的SVG字节码转换成纯文本,不会和HTML的标签、特殊字符冲突
- 全程在内存中处理,不需要临时文件,效率更高也更干净
内容的提问来源于stack exchange,提问作者Pankaj Sharma
相关产品推荐
相关产品推荐

