Django创建模型实例时如何实现类变量自增且避免重启后计数归零
计数重置原因
- 你定义在
Project模型下的Count是类属性,这类属性的取值只存在于服务运行的进程内存中,不会写入数据库持久存储。当你关闭电脑、重启Django服务时,原有进程的内存数据会被全部清空,新进程启动时会重新加载模型类的代码,自动将Count初始化为你预设的默认值0。 - 现有写法还存在并发隐患:如果服务开启了多进程/多线程模式,不同进程的内存空间相互隔离,每个进程都会维护自己的
Count数值,不仅会出现计数不一致的问题,高并发下还会生成重复的epic_key。
修复方案
需要将计数改为持久化存储的数据库字段,同时加锁避免并发冲突:
- 修改
models.py中Project模型的定义,新增持久化计数字段:
class Project(models.Model): # 新增持久化计数字段 saga_count = models.IntegerField(default=0, verbose_name="关联Saga计数") # 补充你代码中用到的key字段(如果之前已经定义可以忽略这行) key = models.CharField(max_length=20, unique=True, verbose_name="项目标识") manager = models.ForeignKey( User, related_name="project_managing", on_delete=models.SET_NULL, blank=True, null=True, )
修改后需要执行python manage.py makemigrations和python manage.py migrate命令将字段同步到数据库。
- 修改
signals.py中的信号逻辑,加行锁保证计数的原子性:
from django.db import transaction @receiver(pre_save, sender=Saga) def generate_epic_key(sender, instance, *args, **kwargs): if not instance.epic_key and instance.epic_project: # 开启事务加行锁,避免并发修改导致计数异常 with transaction.atomic(): # 锁定当前关联的Project行,其他修改请求会等待锁释放 project = Project.objects.select_for_update().get(id=instance.epic_project_id) current_num = project.saga_count + 1 instance.epic_key = f"{project.key}-{current_num}" project.saga_count = current_num # 仅更新计数字段,提高执行效率 project.save(update_fields=["saga_count"])
调整后计数会持久存储在数据库中,重启服务不会导致计数重置,同时行锁机制也能避免并发场景下的key重复问题。
内容的提问来源于stack exchange,提问作者Papis Sahine
相关产品推荐
相关产品推荐

