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

如何在Django后台实现可下载的采购发票PDF功能?

在Django后台添加发票PDF下载功能

1. 安装依赖

推荐使用WeasyPrint,它支持将HTML模板转换为PDF,便于自定义发票样式:

pip install weasyprint

2. 创建发票HTML模板

在你的app目录下新建templates/invoice_template.html,编写带样式的发票结构,填充MainPurchases字段:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>采购发票</title>
    <style>
        .invoice-container {
            width: 800px;
            margin: 0 auto;
            font-family: Arial, sans-serif;
        }
        .invoice-header {
            text-align: center;
            border-bottom: 2px solid #000;
            padding-bottom: 10px;
        }
        .invoice-details {
            margin-top: 20px;
            display: flex;
            justify-content: space-between;
        }
        .invoice-items {
            margin-top: 30px;
            width: 100%;
            border-collapse: collapse;
        }
        .invoice-items th, .invoice-items td {
            border: 1px solid #000;
            padding: 8px;
            text-align: left;
        }
        .total-section {
            margin-top: 20px;
            text-align: right;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="invoice-container">
        <div class="invoice-header">
            <h1>采购发票</h1>
        </div>
        <div class="invoice-details">
            <div>
                <p><strong>供应商:</strong> {{ purchase.supplier.name }}</p>
                <p><strong>采购日期:</strong> {{ purchase.date_created|date:"Y-m-d H:i" }}</p>
            </div>
            <div>
                <p><strong>支付方式:</strong> {{ purchase.get_payment_method_display }}</p>
                <p><strong>已付金额:</strong> ${{ purchase.paid_amount }}</p>
            </div>
        </div>
        <table class="invoice-items">
            <thead>
                <tr>
                    <th>商品名称</th>
                    <th>数量</th>
                    <th>单价</th>
                    <th>小计</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>{{ purchase.product.name }}</td>
                    <td>{{ purchase.quantity }}</td>
                    <td>${{ purchase.purchase_price }}</td>
                    <td>${{ purchase.quantity|mul:purchase.purchase_price }}</td>
                </tr>
            </tbody>
        </table>
        <div class="total-section">
            <p>总金额: ${{ purchase.quantity|mul:purchase.purchase_price }}</p>
            <p>未付金额: ${{ purchase.quantity|mul:purchase.purchase_price|sub:purchase.paid_amount }}</p>
        </div>
    </div>
</body>
</html>

需要自定义模板标签处理数值计算,在app目录下创建templatetags/invoice_tags.py:

from django import template

register = template.Library()

@register.filter
def mul(value, arg):
    return value * arg

@register.filter
def sub(value, arg):
    return value - arg

3. 编写PDF生成函数

在app目录下创建utils.py,实现PDF生成逻辑:

from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML

def generate_invoice_pdf(purchase):
    # 渲染HTML模板
    html_content = render_to_string('invoice_template.html', {'purchase': purchase})
    # 生成PDF文件
    pdf_file = HTML(string=html_content).write_pdf()
    
    # 构造下载响应
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = f'attachment; filename="invoice_{purchase.id}.pdf"'
    response.write(pdf_file)
    return response

4. 在Django Admin中添加下载按钮

修改app目录下的admin.py,自定义Admin类并添加下载入口:

from django.contrib import admin
from django.urls import reverse
from django.utils.html import format_html
from .models import MainPurchases
from .utils import generate_invoice_pdf

class MainPurchasesAdmin(admin.ModelAdmin):
    list_display = ('product', 'quantity', 'supplier', 'date_created', 'download_invoice')
    
    def download_invoice(self, obj):
        # 生成下载链接
        url = reverse('admin:download_invoice', args=[obj.id])
        return format_html('<a href="{}" class="button">下载发票PDF</a>', url)
    download_invoice.short_description = '操作'

    # 注册自定义URL
    def get_urls(self):
        from django.urls import path
        urls = super().get_urls()
        custom_urls = [
            path('download-invoice/<int:pk>/', self.admin_site.admin_view(self.download_invoice_view), name='download_invoice'),
        ]
        return custom_urls + urls

    def download_invoice_view(self, request, pk):
        purchase = MainPurchases.objects.get(pk=pk)
        return generate_invoice_pdf(purchase)

admin.site.register(MainPurchases, MainPurchasesAdmin)

5. 测试功能

启动Django服务器,进入Admin后台的MainPurchases列表页,每条数据后会显示「下载发票PDF」按钮,点击即可生成并下载包含指定字段的PDF发票。

如果不想用HTML模板,也可以用reportlab直接绘制PDF,示例如下:

from django.http import HttpResponse
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter

def generate_invoice_pdf(purchase):
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = f'attachment; filename="invoice_{purchase.id}.pdf"'
    
    p = canvas.Canvas(response, pagesize=letter)
    width, height = letter
    
    # 绘制发票内容
    p.drawString(100, height-100, "采购发票")
    p.drawString(100, height-130, f"供应商: {purchase.supplier.name}")
    p.drawString(100, height-160, f"商品: {purchase.product.name}")
    p.drawString(100, height-190, f"数量: {purchase.quantity}")
    p.drawString(100, height-220, f"单价: ${purchase.purchase_price}")
    p.drawString(100, height-250, f"总金额: ${purchase.quantity * purchase.purchase_price}")
    p.drawString(100, height-280, f"已付金额: ${purchase.paid_amount}")
    p.drawString(100, height-310, f"采购日期: {purchase.date_created.strftime('%Y-%m-%d %H:%M')}")
    
    p.showPage()
    p.save()
    return response

内容的提问来源于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.13 08:40:26