Home > Software design >  How to handle IntegrityError unique constraint correctly in Django 3.2
How to handle IntegrityError unique constraint correctly in Django 3.2

Time:10-20

Hello i stacked with that simple thing. I need validation with two fields in model their combination must be unique. These is work almost as want, but after i try to add a new combination it raise IntegrityError instead validation error in my form. Any workaround to handle it?

#Model(is not all field but it not Necessary in my question):

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})

#View:

class AggregateSubnetCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = AggregateSubnet
    template_name = 'Subnet_create.html'
    fields = ('region', 'subnet_ip')
    success_message = "%(subnet_ip)s was created successfully"
    def form_valid(self, form): 
        form.instance.created_by = self.request.user
        form.instance.updated_by = self.request.user
        return super().form_valid(form)

I mean how i can replace: enter image description here to something like this: enter image description here

#UPDATE(SOLVE): #That's solve my problem. I've just override clean method:

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']
        if AggregateSubnet.objects.filter(subnet_ip=subnet_ip).exists() and '172.' not in subnet_ip:
            raise ValidationError(
                ('Invalid value: %(value)s this subnet already exist. Only private ip startswith 172. can be duplicated!'),
                params={'value': subnet_ip},    
            )
        return super().clean()

CodePudding user response:

add this line to your model Meta class:

unique_together = (('subnet_ip', 'region'),)

But keep the constraint in place.

You can also add a validation in the form cleaning process:

class AggSubnet(models.Model):

    def clean(self):
        if self.__class__._default_manager.filter(region=self.region, subnet_ip=self.subnet_ip).exlude(pk=self.pk).exists():
            raise forms.ValidationError(...) 

I use all three of them simultanously just in case.

  • Related