You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:55:30