# Do not save when either of the 2 fields are not unique

**URL:** <https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405>\
**Category:** Using Django\
**Created:** [August 26, 2021, 5:08am UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405 "2021-08-26T05:08:22Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![CalvinTheCat](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/calvinthecat/32/5343_2.png) [@CalvinTheCat](https://forum.djangoproject.com/u/CalvinTheCat)\
**Post date:** [August 26, 2021, 5:08am UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405/1 "2021-08-26T05:08:22Z")

</div>

I have the following codes

models.py:

```
class Device(models.Model):
    hostname = models.CharField(max_length=50, unique=True)
    ipaddr = models.GenericIPAddressField(protocol='ipv4', default='0.0.0.0')
    date_added = models.DateTimeField(default=timezone.now)
    
    
    def __str__ (self):
        return self.hostname

class DeviceDetail(models.Model):
    
    SUBNET_CHOICES = (
    ('16','16'),
    ('17', '17'),
    ('18','18'),
    ('19','19'),
    ('20','20'),
    ('21', '21'),
    ('22', '22'),
    ('23', '23'),
    ('24', '24'),
    ('25', '25'),
    ('26', '26'),
    ('27', '27'),
    ('28', '28'),
    ('29', '29'),
    ('30', '30'),
    )

    DEV_MODS =(
        ('Catalyst 9606R', 'Catalyst 9606R'),
        ('C9300L-48T-4X', 'C9300L-48T-4X')
    )

    hostname = models.CharField(max_length=50)
    mgt_interface = models.CharField(max_length=50)
    mgt_ip_addr = models.GenericIPAddressField(protocol='ipv4', unique=True)
    subnetmask = models.CharField(max_length=2, choices = SUBNET_CHOICES)
    ssh_id = models.CharField(max_length=50)
    ssh_pwd = models.CharField(max_length=50)
    enable_secret = models.CharField(max_length=50)
    dev_mod=models.CharField(max_length=50, choices = DEV_MODS) ##device_model replacement
    DD2DKEY = models.ForeignKey(Device, on_delete=models.CASCADE) ##The key to link up the tables
    
    def __str__ (self):
        return self.hostname

class DeviceInterface(models.Model):
    MODULE_ID_CHOICES = (
        ('TenGigabitEthernet','TenGigabitEthernet'), 
        ('FortyGigabitEthernet','FortyGigabitEthernet'),
        ('GigabitEthernet','GigabitEthernet'),
        ('Ethernet','Ethernet'),        
    )
    
    moduletype = models.CharField(max_length = 50,choices = MODULE_ID_CHOICES)
    firstportid = models.CharField(max_length=50)
    lastportid = models.CharField(max_length=50)
    I2DKEY = models.ForeignKey(Device, on_delete=models.CASCADE) ##The key to link up the tables

    def __str__ (self):
        return self.moduletype

```

forms.py:

```
class DeviceForm(ModelForm):
    class Meta:
        model= Device
        fields= ['hostname']
        labels = {
            "hostname": "Hostname",
            
        }

class DeviceDetailForm(ModelForm):
    class Meta:
        model= DeviceDetail
        fields= ['hostname', 'mgt_interface', 'mgt_ip_addr', 'subnetmask', 'ssh_id', 'ssh_pwd', 'enable_secret', 'dev_mod']
        labels = {
            "mgt_ip_addr": "Management IP Address",
        }
        widgets = {
            'enable_secret': forms.PasswordInput(),
            'ssh_pwd': forms.PasswordInput()
        }

    def clean_hostname(self):
        hostname = self.cleaned_data['hostname']
        if len(hostname) < 8:
            raise forms.ValidationError(f'Hostname needs to be more than 8 character long, {hostname}')
        return hostname

class DeviceInterfaceForm(ModelForm):
    class Meta:
        model= DeviceInterface
        fields= ['moduletype', 'firstportid', 'lastportid']
        labels = {
            "moduletype":"Module Type",
            "firstportid": "First Port ID",
            "lastportid": "Last Port ID"
        }
        widgets = {
            
            'firstportid':forms.TextInput(attrs={
                'placeholder': 'e.g. TenGigabitEthernet1/0/1',
                'class':'form-control',
                'onchange':'portidChange(this.value)'
                }),
            'lastportid':forms.TextInput(attrs={
                'placeholder': 'e.g. TenGigabitEthernet1/0/48',
                'class': 'form-control',
                'onchange':'portidChange(this.value)'
                })
        }

```

views.py:

```
def device_add(request):
    if request.method == "POST":
        device_frm = DeviceForm(request.POST) ##Part A1
        dd_form = DeviceDetailForm(request.POST)
        
        di_formset = modelformset_factory(DeviceInterface, fields=('moduletype', 'firstportid', 'lastportid'), extra=1,max_num=3)
        di_form=di_formset(request.POST)
        if device_frm.is_valid():
        # Create and save the device
        # new_device here is the newly created Device object
            new_device = device_frm.save()
            if dd_form.is_valid():
                # Create an unsaved instance of device detail
                deviceD = dd_form.save(commit=False)
                # Set the device we just created above as this device detail's device
                deviceD.DD2DKEY = new_device
                # If you did not render the hostname for the device detail, set it from the value of new device
                deviceD.hostname = new_device.hostname
                deviceD.save()
                if di_form.is_valid():
                    deviceI=di_form.save(commit=False) 
                    for instances in deviceI:          
                        instances.I2DKEY=new_device
                        instances.save()
                return render(request, 'interface/device_added.html',{'devices':Device.objects.all()})
            return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form, 'di_form':di_form})
        return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form, 'di_form':di_form})
                
        
    else:
        device_frm = DeviceForm()
        dd_form = DeviceDetailForm()
        di_formset = modelformset_factory(DeviceInterface, fields=('moduletype', 'firstportid', 'lastportid'),extra=1, max_num=3)
        di_form=di_formset(queryset = DeviceInterface.objects.none())
        return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form, 'di_form':di_form})

```

As u can see, in my models.py under class device(hostname- unique=true) and class devicedetail(mgt\_ip\_addr - unique = true). So whenever user type the same existing hostname or mgt\_ip\_addr on the page, it should be rejected and not saved in database.

Here is the scenario:

1. User A keys in Testing for hostname and 1.1.1.1 for mgt\_ip\_addr.
2. User B keys in Testing for hostname and 1.1.1.1 for mgt\_ip\_addr.
3. User C: keys in Testing1 for hostname and 1.1.1.1 for mgt\_ip\_addr
4. User D: keys in Testing1 for hostname and 1.1.1.2 for mgt\_ip\_addr

Results:

1. Form get saved as User A is the first user to key in the following hostname and mgt\_ip\_addr **(Worked as intended)**

2. Form is rejected for User B as it has identical hostname and identical mgt\_ip\_addr as User A and does not get saved. **(Worked as intended)**

3. Warning is display saying mgt\_ip\_addr exist already as User A has this mgt\_ip\_addr. But the form still save the part for 1st table (Device) before rejecting the other fields **(Not working as intended)**

4. Warning displayed for hostname existing as User C has this hostname. (Not intended to save User C due to scenario 3). So the forms get rejected **(Working as intended)**

Desired outcome for scenario 3 :  
Warning to display that mgt\_ip\_addr already exist so the form get rejected even though the hostname is different from any existing one

The codes seems to work as intended but at the very backend it got haywire which i dont know why. Can someone suggest what i can do to fix this issue?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 26, 2021, 1:03pm UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405/2 "2021-08-26T13:03:29Z")

</div>

Probably the easiest way to address this is to check all your forms for being valid before doing work on any of them.  
e.g:  
`if device_frm.is_valid() and dd_form.is_valid() and di_form.is_valid():`

---

<div class="post-metadata">

**Author:** ![CalvinTheCat](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/calvinthecat/32/5343_2.png) [@CalvinTheCat](https://forum.djangoproject.com/u/CalvinTheCat)\
**Post date:** [August 27, 2021, 1:33am UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405/3 "2021-08-27T01:33:25Z")

</div>

Can do 3 at once? I thought max was 2. But its okay. I fixed it by moving all the unique fields under 1 model and it work

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 27, 2021, 2:31am UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405/4 "2021-08-27T02:31:32Z")

</div>

> [@CalvinTheCat](#):
>
> I thought max was 2

I’m curious, what have you seen or read that would have given you that impression?

---

<div class="post-metadata">

**Author:** ![CalvinTheCat](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/calvinthecat/32/5343_2.png) [@CalvinTheCat](https://forum.djangoproject.com/u/CalvinTheCat)\
**Post date:** [August 27, 2021, 4:08am UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405/5 "2021-08-27T04:08:45Z")

</div>

Im recalling what i previously do in C which i only did a max of 2. I know its not a good reference but thats what is helping me to understand so far

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 27, 2021, 1:21pm UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405/6 "2021-08-27T13:21:11Z")

</div>

Ok, but that’s not a requirement in C, either. A statement such as:  
`if (function_a() && function_b() && function_c()) { ...`  
is also perfectly valid.

(Not only that, but like Python, C also specifies that logical operators will be performed in the proper sequence and are “short-circuited” as well - if function\_a() is false, then function\_b and function\_c are not evaluated.)

---

<div class="post-metadata">

**Author:** ![CalvinTheCat](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/calvinthecat/32/5343_2.png) [@CalvinTheCat](https://forum.djangoproject.com/u/CalvinTheCat)\
**Post date:** [August 28, 2021, 7:40am UTC](https://forum.djangoproject.com/t/do-not-save-when-either-of-the-2-fields-are-not-unique/9405/7 "2021-08-28T07:40:16Z")

</div>

Thank you for all your explanation! I appreciate it alot !
