models.py
class Job(models.Model):
jobname = models.CharField(max_length = 1000)
owner = models.CharField(max_length = 150)
enabled = models.BooleanField(default = True)
freq_type = models.IntegerField(default = 1)
freq_interval = models.IntegerField(default = 0)
freq_recurrence = models.IntegerField(default = 0)
start_date=models.CharField(max_length=10)
end_date=models.CharField(max_length=10, blank = True)
start_time=models.CharField(max_length=6)
end_time=models.CharField(max_length=6, blank = True)
date_added = models.DateTimeField(default=timezone.now)
date_modified=models.DateTimeField(null = True)
version=models.IntegerField(default = 1)
class Job_detail(models.Model):
job_type=models.IntegerField()
json = models.CharField(max_length = 1000)
jobid = models.ForeignKey(Job, on_delete=models.CASCADE)
class Job_track(models.Model):
status = models.IntegerField(default = 3)
output = models.CharField(max_length=500, blank = True)
location = models.CharField(max_length = 500, blank = True)
jobid = models.ForeignKey(Job, on_delete=models.CASCADE)
jobdetailid = models.ForeignKey(Job_detail, on_delete=models.CASCADE)
forms.py
class JobForm(ModelForm):
class Meta:
model = Job
fields = []
class JobDetailForm(ModelForm):
class Meta:
model = Job_detail
fields = []
exclude = ['jobid']
class JobTrackForm(ModelForm):
class Meta:
model= Job_track
fields = []
exclude = ['jobid', 'jobdetailid']
Within the function of my views:
def device_port_selected(request, pk):
devices = Device.objects.get(pk=pk)
if request.method == "POST":
job = JobForm(request.POST)
jobdetail = JobDetailForm(request.POST)
jobtrack = JobTrackForm(request.POST)
if job.is_valid() and jobdetail.is_valid() and jobtrack.is_valid():
#For Job
j = job.save(commit=False)
hostname = devices.id
print(type(hostname))
ipaddr = devices.ipaddr
print(type(ipaddr))
name = str(hostname) ',' ipaddr
j.jobname=name
current_user = request.user
j.owner = current_user.username
j.enabled = "True"
j.freq_type = 1
j.freq_interval = 0
j.freq_recurrence = 0
servicedate = request.POST.get('servicedate','')
print(servicedate)
j.start_date = servicedate
servicetime = request.POST.get('servicetime','')
print(servicetime)
j.start_time = servicetime
j.version = 1
j.save()
#For Job_detail
jobd = jobdetail.save(commit=False)
selection=request.POST.get('portrange','')
mode=request.POST.get('portmode','')
status=request.POST.get('portstatus','')
portpara1 = request.POST.get('portpara1','')
portpara2 = request.POST.get('portpara2','')
if selection == "":
messages.warning(request, "Please select the ports that you want to configure")
return render(request, 'interface/device_port_selected.html',{'devices':devices, 'righttable':righttable, 'job':job} )
combined={"port_range":selection, "port_mode":mode, "port_status":status, "port_param1":portpara1, "port_param2": portpara2}
combinedfinal = {"device":hostname, "ip":ipaddr, "configuration":combined}
jobd.job_type=1
jobd.json = combinedfinal
jobd.save()
#For Job_track
jobt=jobtrack.save(commit=False)
jobt.status=3
jobt.save()
return redirect('/device/', {'device':Device.objects.all, 'devices':device})
else:
print(job.errors)
print(jobdetail.errors)
print(jobtrack.errors)
return render(request, 'interface/device_port_selected.html',{'devices':devices, 'righttable':righttable} )
else:
job = JobForm(request.POST)
jobdetail = JobDetailForm(request.POST)
jobtrack = JobTrackForm(request.POST)
return render(request, 'interface/device_port_selected.html',{'devices':devices, 'righttable':righttable, 'job':job, 'jobdetail':jobdetail, 'jobtrack':jobtrack} )
When I try to press the submit button in my browser, I get the following error
NOT NULL constraint failed: interface_job_detail.jobid_id
Shouldn't a foreign key be generated by itself if I declare what table it is linked to? I linked the jobid
of Job_detail
table to Job
table. But it does not seem to work. Can anyone explain how am I doing it wrong and show me a way to correct this?
Update:
I removed the exclude
from my forms but I am still getting the same error.
CodePudding user response:
You create and save a Job
instance (named j
) but there is no way the Job_detail
instance (jobd
) will automatically associate itself with that instance. You must specifically populate the foreign key before you save the instance, i.e.
jobd.jobid = j
jobd.save()
similarly for the Job_track
instance (jobt
):
jobt.jobid = j
jobt.jobdetailid = jobd
jobt.save()
As a side note have a look at PEP-8 and try to name your classes (e.g. JobDetail
instead of Job_detail
) and variables (job_d
or better job_detail
instead of jobd
) in compliance with it. Your current naming scheme is confusing.
CodePudding user response:
because you use commit=False, is that not save the instance into db.
This save() method accepts an optional commit keyword argument, which accepts either True or False. If you call save() with commit=False, then it will return an object that hasn’t yet been saved to the database. In this case, it’s up to you to call save() on the resulting model instance. This is useful if you want to do custom processing on the object before saving it, or if you want to use one of the specialized model saving options. commit is True by default.
Another side effect of using commit=False is seen when your model has a many-to-many relation with another model. If your model has a many-to-many relation and you specify commit=False when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isn’t possible to save many-to-many data for an instance until the instance exists in the database.
To work around this problem, every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass. After you’ve manually saved the instance produced by the form, you can invoke save_m2m() to save the many-to-many form data.
you can see this from the documentation :
https://docs.djangoproject.com/en/3.2/topics/forms/modelforms/#the-save-method