基于Django与ReportLab实现PDF渲染及打印功能的技术问询
我来帮你一步步实现每条记录旁的PDF打印按钮功能,核心思路是让PDF生成视图能针对单条记录生成专属内容,再给每条记录添加触发按钮,最后实现PDF加载后自动打印的效果。
步骤1:改造PDF生成视图,支持单条记录
你原来的PDF视图是固定文本,现在要改成接收记录ID,从数据库拉取对应记录并填充到PDF里。这里我用get_object_or_404简化不存在记录的处理:
from django.http import HttpResponse from django.shortcuts import get_object_or_404 from io import BytesIO from reportlab.pdfgen import canvas from reportlab.lib.units import mm from . import models def record_pdf_view(request, record_id): # 获取指定ID的记录,不存在则返回404 record = get_object_or_404(models.record, pk=record_id) # 初始化PDF响应,设置为浏览器内打开(inline)而非下载 response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = f'inline; filename="record_{record_id}.pdf"' buffer = BytesIO() my_canvas = canvas.Canvas(buffer) # 开始写入PDF内容,替换成你实际的record模型字段 textobject = my_canvas.beginText(30 * mm, 65 * mm) textobject.setFont('Times-Roman', 10) textobject.textLine(f"患者姓名: {record.patient_assign.name}") textobject.textLine(f"记录日期: {record.date.strftime('%Y-%m-%d %H:%M')}") textobject.textLine("----------------------------") textobject.textLine(f"记录内容: {record.content}") # 可以继续添加更多字段,比如诊断结果、医生姓名等 my_canvas.drawText(textobject) my_canvas.setTitle(f"患者记录 #{record_id}") my_canvas.showPage() my_canvas.save() pdf = buffer.getvalue() buffer.close() response.write(pdf) return response
步骤2:配置URL路由
在你的app的urls.py里,新增PDF视图的路由,方便模板反向解析:
from django.urls import path from . import views urlpatterns = [ # 保留你原有的患者页面路由 path('patient/<int:id>/', views.patient_page, name='patient_page'), # 新增单条记录的PDF路由 path('record/pdf/<int:record_id>/', views.record_pdf_view, name='record_pdf'), ]
步骤3:在HTML模板添加打印按钮
在patient_page.html的记录循环里,给每条记录加按钮。这里提供两种方案:
方案1:简单链接按钮(手动打印)
点击后在新窗口打开PDF,用户手动点击浏览器打印按钮:
{% for record in rec %} <div class="record-card"> <h4>记录日期: {{ record.date|date:"Y-m-d H:i" }}</h4> <p>{{ record.content }}</p> <!-- 用url标签反向生成PDF链接,传递当前记录ID --> <a href="{% url 'record_pdf' record.id %}" target="_blank" class="btn btn-primary">打印这条记录</a> </div> {% endfor %}
方案2:自动触发打印(更友好)
用JS创建隐藏iframe加载PDF,加载完成后自动弹出打印对话框:
{% for record in rec %} <div class="record-card"> <h4>记录日期: {{ record.date|date:"Y-m-d H:i" }}</h4> <p>{{ record.content }}</p> <button onclick="printSingleRecord({{ record.id }})" class="btn btn-primary">打印这条记录</button> </div> {% endfor %} <script> function printSingleRecord(recordId) { // 创建隐藏iframe加载PDF const iframe = document.createElement('iframe'); iframe.style.display = 'none'; // 替换URL中的占位符为实际记录ID iframe.src = "{% url 'record_pdf' 0 %}".replace('0', recordId); document.body.appendChild(iframe); // 等待PDF加载完成后触发打印 iframe.onload = function() { try { iframe.contentWindow.print(); // 打印完成后移除iframe setTimeout(() => document.body.removeChild(iframe), 1500); } catch (e) { // 若自动打印失败(浏览器安全限制),则打开新窗口让用户手动操作 window.open(iframe.src, '_blank'); document.body.removeChild(iframe); } }; } </script>
额外提示
- 记得根据你实际的
record模型字段调整PDF里的内容,比如如果有diagnosis(诊断)、doctor(医生)字段,直接添加对应的textobject.textLine即可。 - 如果需要更复杂的PDF样式(比如表格、页眉页脚),可以参考ReportLab的官方文档扩展功能,比如用
SimpleDocTemplate代替canvas来构建结构化文档。
内容的提问来源于stack exchange,提问作者murphyj
相关产品推荐
相关产品推荐

