Home > Software design >  Foreign key in Django Models does not seem to auto generate
Foreign key in Django Models does not seem to auto generate

Time:11-03

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

  • Related