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

如何让Django的Model.clean()在保存前正确生效?

解决Django测验应用Admin验证问题

你的问题根源很明确:Question模型的clean()方法直接查询数据库中的旧数据,而Django Admin处理关联的Answer时,会先执行Question的验证,此时修改后的Answer还没写入数据库,导致验证逻辑和实际要保存的内容不匹配。

举个例子:当你把所有答案改成错误保存时,Question的clean先执行,此时数据库里还有之前的正确答案,验证通过;等Answer保存后,数据库里才变成全错误。下次修改回有正确答案时,Question的clean执行时读的是数据库里全错误的旧数据,所以触发错误,但你提交的新答案其实是符合要求的。

正确的解决方案:用InlineFormSet做验证

在Admin层面,通过自定义Answer的Inline表单集来验证,这样能拿到用户提交的最新Answer数据,而不是数据库旧数据。具体步骤如下:

  1. 在你的admin.py中添加以下代码:
from django.contrib import admin
from django.forms import BaseInlineFormSet
from django.core.exceptions import ValidationError
from .models import Quiz, Question, Answer

class AnswerInlineFormSet(BaseInlineFormSet):
    def clean(self):
        super().clean()
        correct_count = 0
        total_answers = 0
        # 遍历所有提交的Answer表单,排除要删除的
        for form in self.forms:
            if form.cleaned_data and not form.cleaned_data.get('DELETE', False):
                total_answers += 1
                if form.cleaned_data['is_correct']:
                    correct_count += 1
        # 验证逻辑
        if correct_count == 0:
            raise ValidationError('至少需要一个正确答案')
        if correct_count == total_answers:
            raise ValidationError('至少需要一个错误答案')

class AnswerInline(admin.TabularInline):
    model = Answer
    formset = AnswerInlineFormSet

class QuestionAdmin(admin.ModelAdmin):
    inlines = [AnswerInline]

# 注册模型
admin.site.register(Quiz)
admin.site.register(Question, QuestionAdmin)
  1. 移除Question模型中的clean()方法,避免和Admin的验证逻辑冲突。

为什么这个方法有效?

InlineFormSet的clean()方法会在所有Answer表单提交后、保存前执行,能直接获取用户提交的最新数据(包括新增、修改的答案),完全避开了数据库旧数据的干扰,验证逻辑和实际要保存的内容完全匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:16:12