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
相关产品推荐
相关产品推荐

