Не сохранять, если одно из 2 полей не уникально (Обновленный вопрос)

У меня следующие коды

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

Как вы можете видеть, в моем models.py в классе device(hostname- unique=true) и class devicedetail(mgt_ip_addr - unique = true). Поэтому, когда пользователь вводит на странице одно и то же существующее имя хоста или mgt_ip_addr, оно должно быть отклонено и не сохранено в базе данных.

< < < <

Выдается предупреждение о том, что mgt_ip_addr уже существует. Но форма все равно сохраняется для таблицы Device. Таким образом, имя хоста ключа Test1, введенного пользователем C, сохраняется в базе данных. Но другие таблицы не сохраняются (нежелательно)

Желаемый результат : Пользователь C вводит test1 для имени хоста и 1.1.1.1 для mgt_ip_addr

Предупреждение о необходимости отображения mgt_ip_addr и отклонение формы для пользователя C.

Может ли кто-нибудь посоветовать мне, что я делаю неправильно?

Хочу поделиться ответом. Невозможно иметь уникальные поля в отдельных таблицах в рамках одной формы. Я не знаю, может я не прав. Но у меня это работает, так что да.

Вернуться на верх