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

Django模型实现年份+递增序号格式自定义ID的方案咨询

方案建议

优先选择:保留默认ID,新增自定义业务ID字段

该方案是生产环境下的最优选择,核心优势如下:

  • 解耦业务规则与数据库主键:你需要的【年份+递增序号】属于业务层面的编号规则,后续如果规则调整(比如需要增加月份、标识前缀等),不需要修改主键关联逻辑,维护成本极低
  • 性能更优:Django默认的自增整数主键作为数据库聚簇索引,查询、外键关联的性能远高于字符串类型的自定义主键,存储开销也更小
  • 兼容性更好:绝大多数Django第三方生态包默认适配自增整数主键,替换主键会增加不必要的适配成本

不推荐:直接替换默认主键为自定义ID

该方案仅在业务强制要求该字段作为唯一主键时考虑,存在明显弊端:

  • 字符串主键会大幅降低索引、关联查询性能
  • 已存在存量数据的情况下做主键迁移风险极高
  • 业务规则调整时需要全表更新主键,关联的外键数据也需要同步修改,运维成本极高
具体实现代码示例
from django.db import models
from django.db.utils import IntegrityError

class YourBusinessModel(models.Model):
    # 保留Django默认自增ID主键
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    # 自定义业务ID,设置不可编辑、唯一约束
    business_id = models.CharField(max_length=7, unique=True, editable=False, verbose_name="业务编号")
    # 其他业务字段...

    def save(self, *args, **kwargs):
        # 仅新增实例时生成业务ID,更新时不修改
        if not self.pk:
            # 增加重试机制避免并发写入导致的编号重复
            max_retries = 3
            for _ in range(max_retries):
                year = self.create_time.year
                # 统计当年已生成的记录数量
                year_count = YourBusinessModel.objects.filter(create_time__year=year).count()
                current_seq = year_count + 1
                # 按需求拼接年份+3位补零序号,示例2021001
                self.business_id = f"{year}{current_seq:03d}"
                try:
                    super().save(*args, **kwargs)
                    break
                except IntegrityError:
                    # 触发唯一约束冲突说明并发抢号,重试生成
                    continue
            else:
                raise RuntimeError("业务编号生成失败,重试次数已达上限")
        else:
            super().save(*args, **kwargs)

注意事项

  • 若单年业务量可能超过999,可调整序号补位长度,比如改为current_seq:04d,同步将business_id的max_length调整为8即可
  • 若并发写入量极高,可以单独维护一张序号生成表,按年份存储当前已分配的最大序号,生成编号时直接查表更新,减少统计查询的开销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 03:24:00