如何在Django的ModelForm的save方法中抛出ValidationError?
Django:让ModelForm save()方法中的验证错误在Admin表单显示警告而非500错误
希望ModelForm的错误处理器能像处理clean()方法中的错误那样,将save()方法中的验证错误显示为管理表单上的警告,而非生成500错误页面。
当前代码(位于admin.py):
from django import forms from django.db import IntegrityError from django.utils.translation import gettext_lazy as _ from django.contrib import admin from .models import X class XForm(ModelForm): def save(self, **kwargs): super().save(**kwargs) try: self.instance.update_more_stuff_based_on_extra_fields_in_the_form() except IntegrityError: raise ValidationError(_("Earth to Monty Python.")) return self.instance class XAdmin(admin.ModelAdmin): form = XForm admin.site.register(X, XAdmin)
当前问题:触发验证错误时会出现调试器的500页面,而非期望的管理表单警告。
注:已有类似问题解决的是在Model的save方法中抛出验证错误的场景,本需求针对的是ModelForm的save方法。
解决方案:将验证逻辑提前到clean()阶段
Django Admin仅会捕获表单验证阶段(即clean()方法执行期间)抛出的ValidationError并显示为表单警告,而save()方法属于验证通过后的执行阶段,此处抛出的异常会被判定为服务器错误(500)。因此需要将验证逻辑移至clean()方法中:
from django import forms from django.db import IntegrityError, transaction from django.utils.translation import gettext_lazy as _ from django.contrib import admin from .models import X class XForm(ModelForm): def clean(self): cleaned_data = super().clean() # 如果表单已有其他错误,直接返回 if self.errors: return cleaned_data temp_instance = self.instance try: if not temp_instance.pk: # 新增实例时,用事务临时保存并验证,之后回滚避免脏数据 with transaction.atomic(): temp_instance.save() temp_instance.update_more_stuff_based_on_extra_fields_in_the_form() transaction.set_rollback(True) else: # 修改实例时,直接调用方法验证 temp_instance.update_more_stuff_based_on_extra_fields_in_the_form() except IntegrityError: raise ValidationError(_("Earth to Monty Python.")) return cleaned_data def save(self, **kwargs): instance = super().save(**kwargs) instance.update_more_stuff_based_on_extra_fields_in_the_form() return instance class XAdmin(admin.ModelAdmin): form = XForm admin.site.register(X, XAdmin)
方案说明
- 在
clean()方法中提前执行目标逻辑,捕获IntegrityError并抛出ValidationError,确保错误被Admin表单处理器捕获并显示为警告。 - 新增实例时,通过事务临时保存实例以满足方法执行要求,随后回滚事务避免产生未提交的脏数据。
- 正式保存时再次调用目标方法完成数据更新,此时逻辑已通过验证,不会触发异常。
内容的提问来源于stack exchange,提问作者ZVFrozel
相关产品推荐
相关产品推荐

