如何让Django的Model.clean()在保存前正确生效?
解决Django测验应用Admin验证问题
你的问题根源很明确:Question模型的clean()方法直接查询数据库中的旧数据,而Django Admin处理关联的Answer时,会先执行Question的验证,此时修改后的Answer还没写入数据库,导致验证逻辑和实际要保存的内容不匹配。
举个例子:当你把所有答案改成错误保存时,Question的clean先执行,此时数据库里还有之前的正确答案,验证通过;等Answer保存后,数据库里才变成全错误。下次修改回有正确答案时,Question的clean执行时读的是数据库里全错误的旧数据,所以触发错误,但你提交的新答案其实是符合要求的。
正确的解决方案:用InlineFormSet做验证
在Admin层面,通过自定义Answer的Inline表单集来验证,这样能拿到用户提交的最新Answer数据,而不是数据库旧数据。具体步骤如下:
- 在你的
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)
- 移除Question模型中的
clean()方法,避免和Admin的验证逻辑冲突。
为什么这个方法有效?
InlineFormSet的clean()方法会在所有Answer表单提交后、保存前执行,能直接获取用户提交的最新数据(包括新增、修改的答案),完全避开了数据库旧数据的干扰,验证逻辑和实际要保存的内容完全匹配。
内容的提问来源于stack exchange,提问作者Oksana Bochina
相关产品推荐
相关产品推荐

