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

Django:如何在.save()前(.clean()方法中)访问ManyToManyField关联

背景

目标

我有一个模型,需要根据其类型关联不同对象,因此在模型的.clean()方法中做验证:如果是"Dialogue"(对话)类型,只能关联dialogue对象(ForeignKeyField);如果是"Mixed"(混合)类型,只能关联mixed_chunk对象(带through模型的ManyToManyField)。

问题

但验证ManyToManyField(mixed_chunks)时遇到了问题:对象未保存获取ID前无法访问该关联。在Admin中保存未关联任何mixed_chunks的"D"类型Evaluation对象时,.clean()方法里的if self.mixed_chunks判断结果为真,触发错误提示。

已尝试方案

我做了打印调试:

  • 选中部分EvalMixedEvalChunkCombo对象时:
    • print(self.mixed_chunks) = "evaluations.MixedEvalChunk.None"
    • print(self.e_eval_mixed_chunk_combos) = "evaluations.EvalMixedEvalChunkCombo.None"
  • 未选中EvalMixedEvalChunkCombo对象时:
    • print(self.mixed_chunks) = "evaluations.MixedEvalChunk.None"
    • print(self.e_eval_mixed_chunk_combos) = "evaluations.EvalMixedEvalChunkCombo.None"
  • 选中dialogue对象时:
    • print(self.dialogue) = 对话对象名称
  • 未选中dialogue对象时:
    • print(self.dialogue) = "None"

这说明提交表单时,对象还没和Admin中分配的ManyToManyField对象建立关联。如果相关Stack Overflow的答案正确,那似乎没法实现这个验证。

我尝试在.clean()方法中调用self.save(),但打印结果完全一样

这个问题不是Admin特有的,创建Evaluation对象时都会出现。

代码

models.py

from scenario.models import Dialogue

class MixedEvalChunk(models.Model):
    difficulty = models.CharField(max_length=15)
    # 其他若干字段...

class EvalMixedEvalChunkCombo(models.Model):
    eval = models.ForeignKey(
        'Evaluation',
        on_delete=models.CASCADE,
        related_name="e_eval_mixed_chunk_combos"
    )
    mixed_eval_chunk = models.ForeignKey(
        MixedEvalChunk,
        on_delete=models.CASCADE,
        related_name="m_eval_mixed_chunk_combos"
    )

class Evaluation(models.Model):
    class EVAL_TYPES(models.TextChoices):
        D = 'D', _('对话')
        S = 'S', _('同声传译')
        T = 'T', _('笔译')
        M = 'M', _('混合')
    type = models.CharField(max_length=1, choices=EVAL_TYPES.choices, default='D')

    dialogue = models.ForeignKey(
        Dialogue,
        blank=True,
        null=True,
        on_delete=models.SET_NULL
    )

    mixed_chunks = models.ManyToManyField(
        MixedEvalChunk,
        blank=True,
        through=EvalMixedEvalChunkCombo
    )

    def clean(self):
        if self.type == 'D':
            if self.mixed_chunks:
                raise ValidationError(_("对话类型的评估只能关联对话对象"))
        elif self.type == 'M':
            if self.dialogue:
                raise ValidationError(
                    {"dialogue": _("混合类型的评估只能关联混合评估片段"),}
                )

admin.py

class MixedEvalChunkInlineAdmin(admin.TabularInline):
    model = Evaluation.mixed_chunks.through
    extra = 0

@admin.register(MixedEvalChunk)
class MixedEvalChunkAdmin(admin.ModelAdmin):
    pass

@admin.register(EvalMixedEvalChunkCombo)
class EvalMixedEvalChunkComboAdmin(admin.ModelAdmin):
    list_display = ["若干字段..."]
    fieldsets = ["若干字段..."]

@admin.register(Evaluation)
class EvaluationAdmin(admin.ModelAdmin):
    fieldsets = ["若干字段..."]
    inlines = (MixedEvalChunkInlineAdmin,)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:20:12