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

Django中如何实现子模型按父级关联序号生成唯一显示ID?

Django实现患者-组织样本的分组唯一标识方案

核心需求回顾

  • 患者的displayed_id由主键哈希生成,避免使用原始PK
  • 每个患者的样本标识格式为[患者displayed_id]-[患者内序号],如H6F4A-1、H6F4A-2
  • 删除样本后,剩余样本的编号不允许变更(适配物理条形码)
  • 多人并发创建样本时,必须保证序号唯一,无竞态条件

可靠实现方案

核心思路是给TissueSample新增一个存储「患者内样本序号」的字段,通过数据库原子操作生成该序号,避免并发冲突,再组合患者的displayed_id得到最终的样本标识。

修改后的模型代码

from django.db import models, transaction
# 假设h_encode是你已实现的哈希函数

class Patient(models.Model):
    # 其他业务字段...
    displayed_id = models.CharField(max_length=512, editable=False, unique=True)
    
    def save(self, *args, **kwargs):
        # 仅首次创建时生成displayed_id(避免重复哈希)
        if not self.pk:
            super().save(*args, **kwargs)
            self.displayed_id = h_encode(self.pk)
            super().save(*args, **kwargs)
        else:
            super().save(*args, **kwargs)

class TissueSample(models.Model):
    # 其他业务字段...
    displayed_id = models.CharField(max_length=512, editable=False, unique=True)
    patient = models.ForeignKey(Patient, on_delete=models.RESTRICT)
    # 新增字段:存储该患者下的样本序号,仅内部使用
    patient_sample_number = models.PositiveIntegerField(editable=False)

    def save(self, *args, **kwargs):
        # 仅创建新样本时生成序号和标识
        if not self.pk:
            # 原子事务+行锁,避免并发竞态
            with transaction.atomic():
                # 锁定当前患者的所有样本记录,强制并发请求排队
                patient_samples = TissueSample.objects.filter(patient=self.patient).select_for_update()
                # 获取当前患者的最大样本序号,无样本则从1开始
                max_num = patient_samples.aggregate(max_num=models.Max('patient_sample_number'))['max_num'] or 0
                self.patient_sample_number = max_num + 1
                # 组合生成最终的样本标识
                self.displayed_id = f"{self.patient.displayed_id}-{self.patient_sample_number}"
        super().save(*args, **kwargs)

方案可靠性说明

  1. 无竞态条件:
    • 使用transaction.atomic()包裹序号生成逻辑,保证整个操作的原子性
    • select_for_update()会锁定当前患者的所有样本记录,并发创建请求会等待锁释放后再执行,避免两个请求同时拿到相同的最大序号
  2. 编号稳定性:
    • patient_sample_number存储在数据库中,删除样本时不会重新分配序号,剩余样本的displayed_id完全保留
  3. 全局唯一性:
    • displayed_id设置了unique=True,数据库层面强制保证标识唯一,需确保h_encode是单射函数(不同PK生成不同哈希)
  4. 性能影响可控:
    • 仅针对单个患者的样本记录加锁,不会影响其他患者的样本创建操作,并发场景下性能损耗极低

迁移注意事项

如果是已有数据的系统,需要执行以下步骤:

  1. 新增patient_sample_number字段(允许为空,后续填充)
  2. 编写数据迁移脚本,按患者分组,给每个患者的样本按创建时间(或原有逻辑)分配1、2、3...的序号
  3. 批量更新所有样本的displayed_id为患者displayed_id-序号的格式
  4. 修改字段为非空(null=False)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 10:43:10