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

Django如何设计模型存储关联对应工作流字段的项目元数据

解决方案

你完全不需要为每个工作流单独编写模型,使用通用的实体-属性-值(EAV)结构即可实现动态表单的元数据存储,后续新增工作流、调整元数据字段都不需要修改数据库表结构,维护成本极低。

第一步:补充缺失的关联模型(按需选择)

你当前的模型里没有存储下拉类型字段选项的结构,如果需要支持下拉框的预定义选项配置,先加一个选项关联模型:

class MetadataFieldOption(models.Model):
    id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True)
    field = models.ForeignKey(MetadataField, on_delete=models.CASCADE, related_name="options")
    value = models.CharField(max_length=200)
    sort = models.IntegerField(default=0, verbose_name="排序值,控制下拉选项展示顺序")

    def __str__(self):
        return self.value

    class Meta:
        ordering = ["sort"]

第二步:编写核心的元数据值存储模型

这张表是核心,统一存储所有项目的元数据录入值,通过外键关联项目和对应的元数据字段即可:

class ProjectMetadataValue(models.Model):
    id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True)
    project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="metadata_values")
    field = models.ForeignKey(MetadataField, on_delete=models.CASCADE)
    # 统一用TextField存储值,兼容长文本、布尔值字符串、下拉选项值
    value = models.TextField(blank=True, null=True)
    # 下拉类型可以直接关联选项实例,非下拉类型留空即可
    selected_option = models.ForeignKey(
        MetadataFieldOption,
        on_delete=models.SET_NULL,
        null=True,
        blank=True
    )
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

    class Meta:
        # 强制同一个项目下,同一个元数据字段只能有一条值记录,避免重复脏数据
        unique_together = ("project", "field")

必须做的业务层校验

模型层只负责存储结构,写入数据的时候必须在业务逻辑里加两层校验,避免非法数据:

  • 字段归属校验:当前写入的field必须属于该项目关联工作流绑定的元数据字段集合,禁止写入不属于当前工作流的字段
  • 字段值合法性校验:
    • 文本类型(TXT):校验文本长度、格式符合要求
    • 复选框类型(CB):校验值为合法布尔值(True/False或对应格式的字符串)
    • 下拉类型(DD):校验传入的选项属于该字段下配置的可选选项范围

使用示例

获取项目的元数据、渲染动态表单、查询值都非常简单:

# 1. 获取指定项目的动态表单结构(即该项目关联工作流下的所有元数据字段)
project = Project.objects.select_related("workflow").get(id="你的项目ID")
form_fields = MetadataField.objects.filter(workflow=project.workflow).prefetch_related("options")

# 2. 获取该项目已经录入的所有元数据值
saved_values = {
    value.field_id: value 
    for value in project.metadata_values.select_related("field", "selected_option")
}

# 3. 渲染表单时,循环form_fields,从saved_values里取对应已存值回显即可

这种方案的扩展性很强:后续新增字段类型(比如数字、日期、附件上传),只需要在MetadataField.FIELD_TYPE里加新的类型选项,补充对应的校验逻辑即可,不需要修改存储结构。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 06:57:30