自定义PDF打印命令:基于Django模型生成可打印发票的Views实现求助
分步实现采购发票的可打印格式与PDF生成
一、视图层:从数据库获取数据并渲染模板
针对你的PurchaseItem模型,先实现基础视图获取单条采购记录,渲染成可打印HTML页面,后续可扩展为批量处理的列表视图。
函数式视图示例
# views.py from django.shortcuts import get_object_or_404, render from .models import PurchaseItem def purchase_invoice(request, item_id): # 从数据库获取指定ID的采购记录 purchase_item = get_object_or_404(PurchaseItem, id=item_id) # 计算合计金额(数量×采购单价) total_amount = purchase_item.quantity * purchase_item.purchase_price # 将数据传入模板 context = { 'item': purchase_item, 'total_amount': total_amount, } return render(request, 'purchase_invoice.html', context)
配置路由
在urls.py中添加对应URL规则:
# urls.py from django.urls import path from . import views urlpatterns = [ path('invoice/<int:item_id>/', views.purchase_invoice, name='purchase_invoice'), ]
二、HTML模板:实现可打印专属样式
创建templates/purchase_invoice.html,利用CSS的@media print控制打印样式,确保输出符合发票格式:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>采购发票</title> <style> /* 基础页面样式 */ body { font-family: Arial, sans-serif; padding: 20px; } .invoice-header { text-align: center; margin-bottom: 30px; } .invoice-details { width: 100%; border-collapse: collapse; } .invoice-details th, .invoice-details td { border: 1px solid #000; padding: 8px; text-align: left; } .total-row { font-weight: bold; } /* 打印专属样式 */ @media print { body { padding: 0; } /* 隐藏打印不需要的元素 */ .no-print { display: none; } /* 设置A4页面规格 */ @page { size: A4; margin: 1cm; } } </style> </head> <body> <div class="no-print"> <button onclick="window.print()">打印发票</button> </div> <div class="invoice-header"> <h1>采购发票</h1> <p>发票编号: {{ item.id }}</p> <p>日期: {{ item.date_created|date:"Y-m-d H:i" }}</p> </div> <table class="invoice-details"> <thead> <tr> <th>供应商</th> <th>商品名称</th> <th>数量</th> <th>采购单价</th> <th>应付金额</th> <th>已付金额</th> </tr> </thead> <tbody> <tr> <td>{{ item.supplier.name }}</td> <td>{{ item.product.name }}</td> <td>{{ item.quantity }}</td> <td>¥{{ item.purchase_price }}</td> <td>¥{{ total_amount }}</td> <td>¥{{ item.paid_amount }}</td> </tr> <tr class="total-row"> <td colspan="4" align="right">未付金额:</td> <td colspan="2">¥{{ total_amount|sub:item.paid_amount }}</td> </tr> </tbody> </table> </body> </html>
注:模板中的|sub是自定义差值过滤器,需在templatetags目录下创建文件实现:
# templatetags/custom_filters.py from django import template register = template.Library() @register.filter def sub(value, arg): return value - arg
使用时在模板顶部添加{% load custom_filters %}。
三、自定义Django命令:批量生成PDF发票
使用WeasyPrint库将HTML转为PDF,先安装依赖:
pip install weasyprint
创建自定义命令文件management/commands/generate_invoice_pdf.py:
# management/commands/generate_invoice_pdf.py from django.core.management.base import BaseCommand, CommandError from django.template.loader import render_to_string import weasyprint from django.conf import settings import os from ...models import PurchaseItem class Command(BaseCommand): help = '生成指定采购记录的PDF发票' def add_arguments(self, parser): # 支持按单条记录ID或供应商ID筛选 parser.add_argument('--item-id', type=int, help='单个采购记录ID') parser.add_argument('--supplier-id', type=int, help='供应商ID,生成该供应商所有采购记录的PDF') def handle(self, *args, **options): # 创建PDF存储目录 pdf_dir = os.path.join(settings.MEDIA_ROOT, 'invoices') os.makedirs(pdf_dir, exist_ok=True) # 筛选目标采购记录 queryset = PurchaseItem.objects.all() if options['item_id']: queryset = queryset.filter(id=options['item_id']) elif options['supplier_id']: queryset = queryset.filter(supplier_id=options['supplier_id']) else: raise CommandError('必须指定--item-id或--supplier-id参数') if not queryset.exists(): raise CommandError('未找到符合条件的采购记录') # 批量生成PDF for item in queryset: total_amount = item.quantity * item.purchase_price context = { 'item': item, 'total_amount': total_amount, } # 渲染HTML内容 html_content = render_to_string('purchase_invoice.html', context) # 生成PDF文件 pdf_file = weasyprint.HTML(string=html_content).write_pdf() # 保存到指定路径 pdf_path = os.path.join(pdf_dir, f'invoice_{item.id}.pdf') with open(pdf_path, 'wb') as f: f.write(pdf_file) self.stdout.write(self.style.SUCCESS(f'已生成PDF: {pdf_path}'))
命令使用示例
- 生成单条采购记录的PDF:
python manage.py generate_invoice_pdf --item-id 1
- 生成指定供应商所有采购记录的PDF:
python manage.py generate_invoice_pdf --supplier-id 5
内容的提问来源于stack exchange,提问作者Sesshōmaru
相关产品推荐
相关产品推荐

