Reputation: 97
To all the pros out there. I finally figure out the issue i am having and I have read the foreign key posts in the past but none answer the question i have. My knowledge of foreign key is to link 2 tables while 1 of the table has a pre stored input so the foreign key takes the pre stored input to link to the 2nd table. Now my question comes: Is there a way to use foreign key on new data? Such as using django form with 2 models. Lets say I have this page which is to add a totally new device (None of the 2 tables have any info on this new device). And when i key in the forms. I want to allow saving of the 1st model then pass on (lets say 1st model have the field of 'hostname' and 'ipaddr') 'hostname' to the 2nd table as foreign key so the rest of the fields( model 2) within the same form get saved. Is this possible?
I have my existing codes but it is not doing the above at all. It is currently registering the new device to a pre stored device at the moment and i dont know what how to change it as my knowledge of foreign key = need existing updates. I know how to do it if the page requires a login and sync the data to the log in user but this web doesnt require log in. Below are the codes:
views.py
def device_add(request):
if request.method == "POST":
device_frm = DeviceForm(request.POST) ##Part A1
dd_form = DeviceDetailForm(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.device = 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()
return render(request, 'interface/device_added.html',{'devices':device})
else:
device_frm = DeviceForm()
dd_form = DeviceDetailForm()
di_frm = DeviceInterfaceForm()
return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form})
models.py
class Device(models.Model):
hostname = models.CharField(max_length=50)
ipaddr = models.CharField(max_length=15)
date_added = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.hostname
class DeviceDetail(models.Model):
hostname = models.CharField(max_length=50)
mgt_interface = models.CharField(max_length=50)
mgt_ip_addr = models.CharField(max_length=30)
subnetmask = models.CharField(max_length=30)
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)
device_model = models.ForeignKey(Device, on_delete=models.CASCADE)
def __str__(self):
return self.hostname
forms.py
class DeviceForm(ModelForm):
class Meta:
model= Device
fields= ['hostname', 'ipaddr']
class DeviceDetailForm(ModelForm):
class Meta:
model= DeviceDetail
fields= ['hostname', 'mgt_interface', 'mgt_ip_addr', 'subnetmask', 'ssh_id', 'ssh_pwd', 'enable_secret', 'dev_mod']
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
More details in pic: So currently my form has Model: drop down box. This field is required to select a previous stored hostname to link this new device i registered. It is required as if i remove this, the form doesnt saved on the 2nd model: DeviceDetail. Currently this field appear due to the following codes in html: This part is removed
<div class="row">
<div class="col-md-5">
<div class="form-group">
<label for="{{dd_form.dev_mod_id.id_for_label}}">Model<span
class="text-danger">*</span></label>
{{dd_form.device_model}}
</div>
</div>
</div>
What I want to do is to remove this field and let it do its work at the back. Such as when i load this page(form) it doesnt have this field and when i key in all the details and press save. At the code, it takes the hostname i input and pass it on to the foreign key (Currently it takes the pre stored hostname as the foreign key) then saved this new hostname and the other details in the 2nd table.
Below is for the database:
This is for device table once i add save new data
Look at the value 11 beside the column with the input of Catalyst 9606R
This value 11 comes the id from the device table (Pre stored hostname)(This happens due to the module drop down box which appear in the form to ask me choose a previously stored hostname
This is not i need. I need the new id which is 61 from the 3rd image
Upvotes: 0
Views: 81
Reputation: 12078
From what I understand, you want to create both Device
and DeviceDetail
in one POST.
To support this, first remove device_model
from the form and don't render it in your template (you don't have to, because we are putting a value for it later):
class DeviceDetailForm(ModelForm):
class Meta:
model= DeviceDetail
fields = [
'hostname', 'mgt_interface', 'mgt_ip_addr', 'subnetmask',
'ssh_id', 'ssh_pwd', 'enable_secret'
] # Remove 'device_model'
Then in your views, save the device first. Then use that newly created device as foreign key of the device detail we are about to create:
def device_add(request):
if request.method == "POST":
device_frm = DeviceForm(request.POST)
dd_form = DeviceDetailForm(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.device_model = 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()
Upvotes: 1