Can't get past this: builtins.ValueError: Cannot add "<Applicant: UserName>": the value for field "applicant" is None

I’m getting the following (strange) error from Django:

[....]

File "C:\Python38\Lib\site-packages\django\core\handlers\exception.py", line 49, in inner
response = response_for_exception(request, exc)
File "C:\Python38\Lib\site-packages\django\core\handlers\exception.py", line 111, in response_for_exception
log_response(
File "C:\Python38\Lib\site-packages\django\utils\log.py", line 225, in log_response
getattr(logger, level)(
File "C:\Python38\Lib\logging\__init__.py", line 70, in error
File "C:\Python38\Lib\logging\__init__.py", line 1906, in _LogErrorReplacement
A number of optional keyword arguments may be specified, which can alter
File "C:\Python38\Lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Python38\Lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Python38\Lib\site-packages\django\views\generic\base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Python38\Lib\site-packages\django\utils\decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "C:\Python38\Lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view
return view_func(request, *args, **kwargs)
File "C:\Python38\Lib\site-packages\django\utils\decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
![](C:\Program Files (x86)\Wing Pro 8/resources/icons/bookmarks_excpanel.png) File "C:\Users\fruit\OneDrive\Desktop\FairWorkCycle\jobsapp\decorators.py", line 19, in wrap
return function(request, *args, **kwargs)
![](C:\Program Files (x86)\Wing Pro 8/resources/icons/bookmarks_excpanel.png) File "C:\Users\fruit\OneDrive\Desktop\FairWorkCycle\jobsapp\views\employee.py", line 45, in dispatch
return super().dispatch(self.request, *args, **kwargs)
File "C:\Python38\Lib\site-packages\django\views\generic\base.py", line 101, in dispatch
return handler(request, *args, **kwargs)
File "C:\Python38\Lib\site-packages\django\views\generic\edit.py", line 196, in post
return super().post(request, *args, **kwargs)
File "C:\Python38\Lib\site-packages\django\views\generic\edit.py", line 144, in post
return self.form_valid(form)
File "C:\Python38\Lib\site-packages\django\views\generic\edit.py", line 127, in form_valid
self.object = form.save()
![](C:\Program Files (x86)\Wing Pro 8/resources/icons/bookmarks_excpanel.png) File "C:\Users\fruit\OneDrive\Desktop\FairWorkCycle\accounts\forms.py", line 154, in save
workcycle[0].applicants.add(applicant)
File "C:\Python38\Lib\site-packages\django\db\models\fields\related_descriptors.py", line 949, in add
self._add_items(
File "C:\Python38\Lib\site-packages\django\db\models\fields\related_descriptors.py", line 1125, in _add_items
target_ids = self._get_target_ids(target_field_name, objs)
File "C:\Python38\Lib\site-packages\django\db\models\fields\related_descriptors.py", line 1061, in _get_target_ids
raise ValueError(

builtins.ValueError: Cannot add "<Applicant: Daniel2 Donnelly2>": the value for field "applicant" is None

Here are the relevant models for my jobs app:

from django.db import models
from django.urls import reverse
from django.utils import timezone

from accounts.models import User
from tags.models import Tag

from .manager import JobManager
from jobs.settings import MAX_TAG_LENGTH, MAX_JOB_TAGS

JOB_TYPE = (("1", "Full time"), ("2", "Part time"), ("3", "Internship"))

class Job(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=300)
    description = models.TextField()
    location = models.CharField(max_length=150)
    type = models.CharField(choices=JOB_TYPE, max_length=10)
    category = models.CharField(max_length=100)
    last_date = models.DateTimeField()
    company_name = models.CharField(max_length=100)
    company_description = models.CharField(max_length=300)
    website = models.CharField(max_length=100, default="")
    created_at = models.DateTimeField(default=timezone.now)
    filled = models.BooleanField(default=False)
    salary = models.IntegerField(default=0, blank=True)
    tags = models.ManyToManyField(Tag)
    
    objects = JobManager()

    class Meta:
        ordering = ["id"]

    def get_absolute_url(self):
        return reverse("jobs:jobs-detail", args=[self.id])

    def __str__(self):
        return self.title
    
    @property
    def applicant_count(self):
        workcycle = WorkCycle.objects.get(job=self)
        return workcycle.applicants.count


class Applicant(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name="applicants")
    created_at = models.DateTimeField(default=timezone.now)
    comment = models.TextField(blank=True, null=True)
    status = models.SmallIntegerField(default=1)

    class Meta:
        ordering = ["id"]
        unique_together = ["user", "job"]

    def __str__(self):
        return self.user.get_full_name()

    @property
    def get_status(self):
        if self.status == 1:
            return "Pending"
        elif self.status == 2:
            return "Accepted"
        else:
            return "Rejected"


class Favorite(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name="favorites")
    created_at = models.DateTimeField(default=timezone.now)
    soft_deleted = models.BooleanField(default=False)

    def __str__(self):
        return self.job.title


class WorkCycle(models.Model):
    job = models.ForeignKey(Job, on_delete=models.CASCADE)
    applicants = models.ManyToManyField(Applicant)

    @classmethod
    def create(cls, job):
        workcycle = cls(job=job)
        tags = [str(tag) for tag in job.tags.all()]
        
        users = User.objects.filter(tags_string__contains=tags[0], role="employee")  # TODO Check
        
        for tag in tags[1:]:
            users = User.objects.filter(tags_string__contains=tag)
            if not users:
                break

        workcycle.save()    # BUGFIX: Save call must go prior to many-to-many field editing (or weird "object needs id" exception)        
        
        for user in users.order_by('?'):    # Return users in random order
            applicant = Applicant(user=user, job=job, created_at=timezone.now(), comment="(TODO)")
            applicant.save()
            workcycle.applicants.add(applicant)
        
        return workcycle
    
    def __str__(self):
        return f'Work cycle for Job ID: {self.job.id}'

This happened immediately after I added the WorkCycle update code in the User update code here:

class EmployeeProfileUpdateForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(EmployeeProfileUpdateForm, self).__init__(*args, **kwargs)
        self.fields["first_name"].widget.attrs.update({"placeholder": "Enter First Name"})
        self.fields["last_name"].widget.attrs.update({"placeholder": "Enter Last Name"})

    class Meta:
        model = User
        fields = ["first_name", "last_name", "tags"] # "gender"]
        
    def clean_tags(self):
        tags = self.cleaned_data["tags"]
        if len(tags) < MAX_JOB_TAGS:
            raise forms.ValidationError(f'You need at least {MAX_JOB_TAGS} to match any jobs.')
        elif len(tags) > MAX_USER_TAGS:
            raise forms.ValidationError(f"You can't add more than {MAX_USER_TAGS} tags")
        return tags

    def save(self, commit=True):
        user = super(EmployeeProfileUpdateForm, self).save(commit=False)
        if commit:
            user.save()
            tags = self.cleaned_data["tags"]
            for tag in tags:
                user.tags.add(tag)
            user.tags_string = ';'.join(str(tag) for tag in tags)   # TODO manage delimiter
            user.save()
            
            # Make sure we add new users to wherever they fit into the jobs
            jobs = Job.objects.filter(tags__in=tags)
            
            for job in jobs:
                workcycle = WorkCycle.objects.filter(job=job)
                if workcycle.count():
                    applicant = Applicant(user=user, job=job, created_at=timezone.now(), comment="(TODO)")
                    workcycle[0].applicants.add(applicant)
            
        return user    

The site works prior, but is now broken. I have to update the job applicant pool for every job where the user’s skill tags subsume a given job’s tags. There is no “applicant” field in any of my code, so I don’t know what the error is concerning.

Changed the form save() code to:

    def save(self, commit=True):
        user = super(EmployeeProfileUpdateForm, self).save(commit=False)
        if commit:
            user.save()
            tags = self.cleaned_data["tags"]
            for tag in tags:
                user.tags.add(tag)
            user.tags_string = ';'.join(str(tag) for tag in tags)   # TODO manage delimiter
            user.save()
            
            # Make sure we add new users to wherever they fit into the jobs
            jobs = Job.objects.filter(tags__in=tags)
            
            for job in jobs:
                applicant = Applicant.objects.filter(user=user, job=job)
            
                if applicant.count() == 0:
                    applicant = Applicant(user=user, job=job, created_at=timezone.now(), comment="(TODO)")
                    applicant.save()
                    
                    workcycle = WorkCycle.objects.filter(job=job)
                    
                    if workcycle.count():
                        workcycle[0].applicants.add(applicant)
            
        return user