Django验证实现:Name与Address字段保存后禁止修改
Django实现模型字段保存后不可修改的验证机制
方案一:重写模型clean方法(推荐)
通过重写模型的clean()方法,在验证阶段检查字段是否被修改,该方法会在表单提交、Admin保存等场景自动触发,能友好返回错误提示。
from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ class Institution(CustomModel): name = models.CharField(max_length=256, null=False, blank=False, verbose_name=_('Name')) address = models.ForeignKey('Address', on_delete=models.PROTECT, null=False, blank=False, verbose_name=_('Address')) def clean(self): super().clean() # 仅针对已存在的实例(已有主键)做检查 if self.pk is not None: original = Institution.objects.get(pk=self.pk) # 检查name字段是否被修改 if self.name != original.name: raise ValidationError({'name': _('此字段不可修改')}) # 检查address字段是否被修改 if self.address != original.address: raise ValidationError({'address': _('此字段不可修改')})
说明:这里针对不同字段分别抛出错误,能让用户清楚看到是哪个字段不能修改;如果不需要区分字段,也可以抛出统一的错误信息。
方案二:重写save方法强制拦截
如果需要在保存环节强制阻止修改(即使验证被绕过),可以重写save()方法,但该方式的错误不会自动在表单中展示,建议配合clean方法使用。
class Institution(CustomModel): # 字段定义保持不变 def save(self, *args, **kwargs): if self.pk is not None: original = Institution.objects.get(pk=self.pk) if self.name != original.name or self.address != original.address: raise ValueError(_('Name和Address字段不可修改')) super().save(*args, **kwargs)
方案三:使用pre_save信号全局拦截
通过Django的pre_save信号,在任何保存操作前触发检查,适合需要全局拦截的场景,但同样需要手动处理错误提示。
from django.db.models.signals import pre_save from django.dispatch import receiver from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ @receiver(pre_save, sender=Institution) def check_institution_immutable_fields(sender, instance, **kwargs): if instance.pk is not None: original = sender.objects.get(pk=instance.pk) if instance.name != original.name or instance.address != original.address: raise ValidationError(_('此字段不可修改'))
额外提示
- 对比ForeignKey字段时,也可以用
instance.address_id != original.address_id直接比较ID,效率更高。 - 若多个模型需要类似逻辑,可封装成Mixin类复用代码。
内容的提问来源于stack exchange,提问作者Yen
相关产品推荐
相关产品推荐

