Django模型能否将自定义属性设为主键并用于API增删改查?
实现方案
该需求完全可以实现,核心思路是把原本作为Python计算属性的custom_id改为数据库真实存储的主键字段,并重写保存逻辑实现你要求的自动生成规则,具体调整如下:
1. 模型类重写
删除原有的@property装饰的custom_id方法,替换为真实的模型字段,同时实现自动生成逻辑:
class A(models.Model): name = models.CharField(max_length=64) # 将custom_id设为主键,字符串类型,禁止手动编辑 custom_id = models.CharField( primary_key=True, max_length=6, editable=False, verbose_name="自定义ID" ) def save(self, *args, **kwargs): # 仅为新增实例生成custom_id,避免修改时覆盖已有值 if not self.custom_id: # 查询当前表中最大的custom_id,计算下一个序号 last_record = A.objects.order_by("-custom_id").first() if last_record: next_num = int(last_record.custom_id[1:]) + 1 else: next_num = 1 # 拼接为A+5位补零的格式,比如1 → A00001 self.custom_id = f"A{next_num:05d}" super().save(*args, **kwargs) def __str__(self): return self.name
关键调整说明
primary_key=True:直接替代Django默认生成的自增id字段,将custom_id设为模型唯一主键,ORM会自动将实例的pk属性映射到该字段editable=False:保证该字段不会被序列化器、管理后台自动渲染为可编辑项,只能由系统自动生成- 重写
save()方法:仅在新增实例时生成custom_id,修改已有实例时不会覆盖原有值,生成逻辑完全匹配你原本要求的A00001格式
2. API接口适配调整
因为custom_id已经是模型主键,绝大多数接口不需要额外修改逻辑:
- POST接口:序列化器只需要声明
name字段即可,custom_id会在实例保存时自动生成,不需要前端传入 - PATCH/DELETE/详情查询接口:如果使用DRF的
ModelViewSet,默认的lookup_field='pk'会自动匹配URL中传入的custom_id(例如/api/a/A00001/),不需要修改路由或查询逻辑 - 如果序列化器原本显式声明了旧的
id字段,只需将其替换为custom_id即可,也可以直接依赖模型pk自动返回该值
3. 数据迁移注意事项
修改模型主键后需要执行迁移操作同步数据库:
- 执行
python manage.py makemigrations生成新的迁移文件 - 执行
python manage.py migrate同步到数据库
如果数据库中已经存在旧的A模型数据,需要先编写数据迁移脚本,把原计算属性生成的
custom_id值(即A+原自增id的格式)填充到新的custom_id字段后再完成主键切换,避免原有数据丢失。
额外提示:当前实现的
custom_id生成逻辑未做并发锁处理,高并发同时新增实例时可能出现重复ID,如果后续有高并发需求可以补充数据库行锁逻辑。
内容的提问来源于stack exchange,提问作者thuantp J
相关产品推荐
相关产品推荐

