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

如何在Django中自动生成带INV前缀的递增发票编号

实现自动生成带INV前缀的递增发票编号

1. 修正模型代码错误

你提供的模型存在两处小问题,先修正:

  • 继承类应为 models.Model 而非 model.Models
  • invoice_number 字段重复赋值,需删除冗余部分

修正后的基础模型:

from django.db import models

class Invoice(models.Model):
    clients_name = models.ForeignKey(Clients, on_delete=models.CASCADE, blank=True, null=True)
    invoice_number = models.CharField(max_length=200, blank=True, null=True)

2. 重写save()方法自动生成编号

在Invoice模型中重写save()方法,实现保存时自动生成格式为INV-XXXX的递增编号:

from django.db import models

class Invoice(models.Model):
    clients_name = models.ForeignKey(Clients, on_delete=models.CASCADE, blank=True, null=True)
    invoice_number = models.CharField(max_length=200, blank=True, null=True)

    def save(self, *args, **kwargs):
        # 仅在新建发票时生成编号(未保存到数据库时self.pk不存在)
        if not self.pk:
            # 获取最后一条发票记录,提取序号并递增
            last_invoice = Invoice.objects.all().order_by('-id').first()
            if last_invoice:
                last_number = int(last_invoice.invoice_number.split('-')[1])
                new_number = last_number + 1
            else:
                # 无历史记录时从1开始
                new_number = 1
            # 格式化序号为4位(如0001),要3位则改为`f'INV-{new_number:03d}'`
            self.invoice_number = f'INV-{new_number:04d}'
        super().save(*args, **kwargs)

3. 表单中隐藏发票号字段

在对应的表单类里,将invoice_number设置为隐藏字段,禁止用户手动修改:

from django import forms
from .models import Invoice

class InvoiceForm(forms.ModelForm):
    class Meta:
        model = Invoice
        fields = ['clients_name', 'invoice_number']
        widgets = {
            'invoice_number': forms.HiddenInput()
        }

高并发场景补充

如果系统存在多用户同时创建发票的情况,直接统计数量可能导致编号重复,可改用数据库计数器避免冲突:

# 先创建一个计数器模型(或用单独表存储)
class InvoiceCounter(models.Model):
    count = models.IntegerField(default=0)

# 在Invoice的save方法中调用
def save(self, *args, **kwargs):
    if not self.pk:
        # 原子操作更新计数器
        counter, created = InvoiceCounter.objects.get_or_create(id=1)
        counter.count += 1
        counter.save()
        self.invoice_number = f'INV-{counter.count:04d}'
    super().save(*args, **kwargs)

内容的提问来源于stack exchange,提问作者KENnie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:40:26