Django: create record from form post in another app

I have 3 apps within a project: registrations Model Registration learners Model:Learner track Model: LearnerTrack

When I create a learner object I've a view in learner_track which had been receiving the learner instance and creating relevant tracking records based on the course the learner was registering on. However, when creating a foreign key relationship it stops working and gives an error:

Cannot assign "UUID('11456134-fab7-41f7-a7be-6bdaf423d1c6')": "LearnerTrack.learnerId" must be a "Learner" instance.

Learner model.py

class Learner(models.Model):
 class Status(models.TextChoices):
       LIVE = 'Live', 'Live'
       COMPLETE = 'Complete', 'Complete'
       DEFERRED = 'Deferred', 'Deferred'
       WITHDRAWN = 'Withdrawn', 'Withdrawn'
 status = models.CharField(
       max_length=25,
       choices = Status,
       default = Status.LIVE
  )
 learnerId = models.UUIDField(primary_key=True, default=uuid.uuid4)
 contractId = models.PositiveIntegerField(default = 1)
 firstname = models.CharField(max_length=150)
 middlename = models.CharField(max_length=150, blank=True, null=True)
 surname = models.CharField(max_length=150)
 uln = models.ForeignKey(Registration, on_delete=models.CASCADE)
 postcode = models.CharField(max_length=8)
 area = models.CharField(max_length=10)
 created = models.DateTimeField(auto_now_add=True)
 funding = models.SmallIntegerField()
 groupId = models.ForeignKey(Group, on_delete=models.PROTECT)
 courseId = models.ForeignKey(Course, default = 'WMCASec', on_delete=models.CASCADE)
 postcode_code = models.FloatField(default=1.0)

 notes = models.TextField(blank = True, null = True)

 objects = models.Manager() #The default manager
 live = LiveManager()
 complete = CompleteManager()
 deferred = DeferredManager()
 withdrawn = WithdrawnManager()

 def clean(self):
      if self.postcode:
           self.postcode = self.postcode.replace(" ","").upper()
           #all postcode data saved in same way


 def __str__(self):
     return f"{self.learnerId}"
 
 def get_absolute_url(self):
      return reverse('learner-detail', args=[str(self.learnerId)])

 def save(self, *args, **kwargs):
    super(Learner, self).save(*args, **kwargs)

 class Meta:
     ordering = ['surname']
     indexes = [models.Index(fields=['-created'])]

learners view.py

def add_new_learner(request, uln, *args, **kwargs):
registration = Registration.objects.get(uln=uln)
learner_instance = Learner.objects.filter(uln=uln)
learners = Learner.objects.all()
registered_groups = list(learner_instance)
initial_dict = {
    'firstname' : registration.firstname,
    'middlename' : registration.middlename,
    'surname' : registration.surname,
    'uln' : registration.uln,
    'postcode' : registration.postcode,
    'area' : registration.area,
    'postcode_code' : registration.postcode_code,
    'ethnicity' : registration.ethnicity,
    'funding' : registration.funding,
    'notes':registration.notes,
        }
   
if request.method == 'POST':
    form = CreateLearnerForm(request.POST or None)
    
    if form.is_valid():
        form.save(*args, **kwargs)

        return HttpResponseRedirect("/learners/learner_list/") 
               
else:
    form = CreateLearnerForm(request.POST or None, initial = initial_dict)  

context = {"form":form, 'learners':learners, 'registration':registration, "learner_instance":learner_instance, "registered_groups":registered_groups,
            }
return render(request, 'learners/add_new_learner.html', context,)

track models.py

class LearnerTrack(models.Model):
 contractId = models.PositiveIntegerField(default=1)
 learnerId = models.ForeignKey('learners.Learner', on_delete=models.CASCADE)
 groupId =  models.CharField(max_length=20, null=True, blank=True)
 firstname = models.CharField(max_length=50, null=True, blank=True)
 surname = models.CharField(max_length=50, null=True, blank=True)
 courseId = models.CharField(max_length=20, null=True, blank=True)
 aimId = models.CharField(max_length=20, null=True, blank=True)
 uln = models.PositiveBigIntegerField()
 startDate = models.DateField(null=True, blank=True)
 endDate = models.DateField(null=True, blank=True)
 achieved = models.BooleanField(default=False)
 pfrStart = models.PositiveBigIntegerField(default=0)
 pfrEnd = models.PositiveIntegerField(default=0)
 funding = models.FloatField(default=0.00)
 notes = models.CharField(max_length=1000, null=True, blank=True)
 created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
 var = models.PositiveIntegerField(default = 0) # store variables like hours for WRAP

 class Meta:
   unique_together = ('uln', 'aimId')

 def __str__(self):
      return f"{self.firstname} {self.surname}"
 

 


@receiver(post_save, sender='learners.Learner')
def create_profile(sender, instance, created, **kwargs):
aims = CourseAim.objects.all()

if created:        
    for aim in aims:
        pcode = 1.0
        if aim.uplift == True:
            pcode = instance.postcode_code

        if aim.courseId == instance.courseId:
            
                LearnerTrack.objects.create(learnerId=instance.learnerId, groupId = instance.groupId,
                courseId=instance.courseId, aimId = aim.aimId, contractId = instance.contractId,
                funding = aim.funding * pcode,
                uln = instance.uln,
                firstname = instance.firstname,
                surname = instance.surname)

I'm new to django so please forgive any rookie errors in coding. I'm eager to learn.

Thank you

That happens because you are trying to assign an UUID where the model expects an object instance:

class LearnerTrack(models.Model):
 ...
 learnerId = models.ForeignKey('learners.Learner', on_delete=models.CASCADE)
 ...

You are drilling down the instance to access the UUID and trying to assign it.

LearnerTrack.objects.create(
    learnerId=instance.learnerId,
    ...
)

Thus, just roll-up and assign the instance directly:

LearnerTrack.objects.create(
    learnerId=instance,
    ...
)

p.s. One good coding practice is to maintain a regular structure while naming your variables and classes. In python snake_case for variables/functions and PascalCase for classes.

Back to Top