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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:57:41