如何在Django 3.2中正确处理唯一约束引发的IntegrityError
问题需求与解决
需要为模型中的region和subnet_ip字段设置组合唯一约束,且仅当subnet_ip不以172.开头时生效。目前已在数据库层面配置该约束,但提交重复的字段组合时,系统会抛出IntegrityError异常,而非在表单内显示友好的验证提示,需将错误提示改为表单内的验证信息。
模型关键代码
class AggSubnet(models.Model): region = models.ForeignKey("db_info.Region", on_delete=models.PROTECT, related_name='get_agg_by_region') subnet_ip = models.GenericIPAddressField() class Meta: constraints = [ models.UniqueConstraint(fields=['subnet_ip','region'], condition=~Q(subnet_ip__startswith='172.'), name='agg_subnet_unique'), ] def __str__(self): return f'{self.region} {self.subnet_ip}/{self.subnet_prefix}' def get_absolute_url(self): return reverse(f'{self.__class__.__name__}{DETAIL_SUFFIX}', kwargs={"pk": self.pk})
视图代码
class AggregateSubnetCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView): model = AggregateSubnet template_name = 'Subnet_create.html' fields = ('region', 'subnet_ip') success_message = "%(subnet_ip)s 创建成功" def form_valid(self, form): form.instance.created_by = self.request.user form.instance.updated_by = self.request.user return super().form_valid(form)
已实现的解决方案
通过重写ModelForm的clean方法,在表单层面实现验证逻辑,避免数据库抛出异常:
class AggregateSubnetForm(forms.ModelForm): class Meta: model = AggregateSubnet fields = ('region', 'subnet_ip', 'subnet_prefix',) def clean(self): cleaned_data = self.cleaned_data subnet_ip = cleaned_data['subnet_ip'] region = cleaned_data['region'] # 匹配数据库约束的组合逻辑,同时校验region和subnet_ip if not subnet_ip.startswith('172.') and AggregateSubnet.objects.filter(subnet_ip=subnet_ip, region=region).exists(): raise ValidationError( ('无效值: %(value)s 该子网已存在。仅以172.开头的私有IP允许重复!'), params={'value': subnet_ip}, ) return super().clean()
注:原解决方案未关联
region字段进行组合校验,此处补充后确保与数据库约束逻辑一致。
内容的提问来源于stack exchange,提问作者Firdaus
相关产品推荐
相关产品推荐

