使用django.utils.crypto的get_random_string出现重复键错误如何解决?
问题原因
- 核心触发原因:你正在为已有数据的表新增带unique约束的short_id字段,Django执行迁移时,对于这类需要批量填充旧数据的场景,只会调用1次你传入的default可调用对象,将返回的同一个值赋值给所有已存在的记录,直接触发唯一键冲突,该问题和随机串本身的碰撞概率无关。
- 潜在遗留问题:就算是无旧数据的新表,直接把
get_random_string当default传入也没有做重复校验,万一出现极低概率的随机串碰撞,写入时仍会报错。
可行解决方法
- 第一步:回滚当前的失败迁移,如果迁移尚未生效,直接删除本次新增字段的迁移文件即可。
- 第二步:修改字段定义,替换为带重复校验的自定义生成函数,避免极端情况的碰撞:
from django.utils.crypto import get_random_string def generate_short_id(): # 循环生成直到拿到未被使用的id while True: short_id = get_random_string(length=12) if not MyModel.objects.filter(short_id=short_id).exists(): return short_id class MyModel(models.Model): # ... 其他原有字段 short_id = models.CharField(default=generate_short_id, max_length=12, unique=True)
- 第三步:分两次完成迁移,避免批量填充时的重复问题:
- 先调整short_id字段配置,暂时去掉unique约束、允许为空,执行第一次迁移,此时旧数据的short_id均为null,不会触发冲突。
- 编写自定义数据迁移脚本,遍历所有旧数据,逐个调用
generate_short_id()填充short_id字段,保证每个值唯一。 - 改回short_id字段的配置,加回unique约束、设置不可为空,执行第二次迁移即可。
内容的提问来源于stack exchange,提问作者aroooo
相关产品推荐
相关产品推荐

