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

Django模型实现固定格式唯一作业编码一次性生成的问题

解决Django Job模型作业编码自动生成与不变性问题

核心思路

仅在Job实例首次创建且未手动指定编码时生成唯一作业编码,后续任何操作(关联Cost、修改作业日期)都保留原有编码;同时支持手动覆盖编码,并通过字段标记编码来源。

具体实现步骤

1. 修改Job模型

添加必要字段并优化save()方法,确保编码仅生成一次:

from django.db import models, IntegrityError, transaction
from django.utils.timezone import now

class Client(models.Model):
    code = models.CharField(max_length=3, unique=True)  # 客户3位标识字段
    # 其他客户相关字段...

class Job(models.Model):
    client = models.ForeignKey(Client, on_delete=models.CASCADE)
    job_date = models.DateField()
    job_code = models.CharField(max_length=11, unique=True, blank=True, null=True)  # 匹配aaaMMnnYYYY格式长度
    code_generated_date = models.DateField(blank=True, null=True)  # 记录编码生成时的日期,后续固定不变
    is_auto_generated = models.BooleanField(default=False)  # 标记编码是否为自动生成

    def save(self, *args, **kwargs):
        # 仅在首次创建且未手动设置job_code时自动生成编码
        if not self.pk and not self.job_code:
            # 确定编码依赖的年月:优先用当前job_date,无则取系统当前日期
            self.code_generated_date = self.job_date or now().date()
            year = self.code_generated_date.year
            month = self.code_generated_date.month
            client_code = self.client.code

            # 处理并发冲突,最多重试3次
            max_retries = 3
            for attempt in range(max_retries):
                try:
                    with transaction.atomic():
                        # 实时统计当月该客户的作业数量,避免并发导致编码重复
                        count = Job.objects.filter(
                            client=self.client,
                            code_generated_date__year=year,
                            code_generated_date__month=month
                        ).count()
                        # 序号补两位(如3→03)
                        sequence = f"{count + 1:02d}"
                        # 拼接生成编码
                        self.job_code = f"{client_code}{month:02d}{sequence}{year}"
                        self.is_auto_generated = True
                        super().save(*args, **kwargs)
                    break
                except IntegrityError:
                    if attempt == max_retries - 1:
                        raise  # 重试失败,抛出原错误
                    # 重试时重新计算计数
                    continue
        elif not self.pk and self.job_code:
            # 手动指定编码的场景
            self.is_auto_generated = False
            super().save(*args, **kwargs)
        else:
            # 已有编码的实例,直接保存不修改编码
            super().save(*args, **kwargs)

2. 解决关联Cost时的编码变更问题

之前的问题根源是每次save()都重新生成编码,现在仅在首次创建时触发生成逻辑,后续关联Cost(无论修改Cost还是通过Cost关联Job)都不会触发编码重新计算,彻底规避唯一性错误和URL失效问题。

3. 作业日期修改不影响编码

code_generated_date字段仅在首次创建时赋值,后续修改job_date不会改变该字段,编码生成逻辑依赖的是code_generated_date的年月,因此编码始终保持不变。

4. 支持手动覆盖编码

job_code字段设置为blank=True, null=True,在Admin后台或自定义表单中可直接手动输入编码,保存时会跳过自动生成逻辑,直接使用手动输入的值,并将is_auto_generated标记为False。

5. Admin后台配置(可选)

如果需要在后台管理中控制编码的编辑权限,可配置Job的Admin类:

from django.contrib import admin
from .models import Job

class JobAdmin(admin.ModelAdmin):
    list_display = ('job_code', 'client', 'job_date', 'is_auto_generated')
    fields = ('client', 'job_date', 'job_code', 'is_auto_generated')
    readonly_fields = ('is_auto_generated',)  # 禁止修改编码来源标记

admin.site.register(Job, JobAdmin)

关键说明

  • 并发处理:通过事务+重试机制避免多请求同时创建同客户当月作业时的编码重复问题
  • 字段标记:is_auto_generated字段可用于后续业务逻辑区分自动/手动编码(比如禁止修改自动生成的编码,或做特殊校验)
  • URL稳定性:编码一旦生成不再变更,作为URL参数使用时不会出现链接失效问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:05:53