如何确保已使用过的custom_id(含已删除条目)永不被重复使用?
嘿,这个问题我碰到过好多次了,其实有几个挺简洁的方案,看你业务需求选就行:
方案一:用软删除替代硬删除(最推荐,改动极小)
不用改你现有的ID生成逻辑,只需要给模型加个布尔字段标记删除状态:
from django.db import models class YourModel(models.Model): custom_id = models.CharField(max_length=32, unique=True) is_deleted = models.BooleanField(default=False) # 其他业务字段...
之后删除操作别用.delete()了,改成标记状态再保存:
# 替代删除的逻辑 obj = YourModel.objects.get(custom_id="xxx") obj.is_deleted = True obj.save()
查询正常数据的时候过滤掉已删除的就行:
active_data = YourModel.objects.filter(is_deleted=False)
这样生成新ID时,你原来的存在性检查(比如YourModel.objects.filter(custom_id=new_id).exists())会自动包含已删除的记录——因为这些记录还在数据库里,custom_id的唯一约束也会直接阻止重复。
这个方案的好处:
- 改动微乎其微,几乎不影响现有业务逻辑
- 能保留历史记录,万一以后要恢复数据也方便
- 从根源上杜绝了已删除ID被复用的可能
方案二:维护一张“已使用ID”独立表(适合必须硬删的场景)
如果硬删除原记录是刚需,那可以单独建个表来存所有用过的custom_id:
class UsedCustomID(models.Model): custom_id = models.CharField(max_length=32, primary_key=True)
然后修改你的ID生成逻辑,每次生成前先查这张表,确认未使用后先存入表再返回:
import random import string def generate_unique_custom_id(): while True: # 生成你想要格式的随机ID new_id = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10)) # 检查已使用ID表 if not UsedCustomID.objects.filter(custom_id=new_id).exists(): UsedCustomID.objects.create(custom_id=new_id) return new_id
删除原记录的时候,不要删UsedCustomID里的对应条目,这样这个ID就永远会被标记为已使用,再也不会被生成。
这个方案逻辑清晰,就是多了一张表需要维护,但完全适配硬删除的需求。
方案三:改用UUID作为custom_id(彻底省心,无需检查)
如果你的custom_id不需要短字符串或者特定格式,直接用UUID生成就行——UUID的重复概率低到可以忽略,而且即使删除记录,新生成的UUID绝对不会和之前的任何一个重复:
import uuid from django.db import models class YourModel(models.Model): custom_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) # 其他业务字段...
这样你连生成和检查逻辑都不用自己写,Django会自动帮你生成唯一的UUID,彻底解决ID复用的问题。唯一的小缺点是UUID是36位的长字符串,看你业务是否能接受。
内容的提问来源于stack exchange,提问作者lapin
相关产品推荐
相关产品推荐

