I'm tring to add jobs to the database through a form. However I get the error " ValueError: Cannot assign "'14'": "Jobs.category" must be a "Category" instance." When I submit. I'm not sure How I can solve it. Category is a foreign key in the Jobs model. The user should be able to chose from categories already existing in the database. This displays in the form however on submitting. The error above is thrown. I'm way in over my head here. I appreciate any guidance.
forms.py
class JobForm(forms.ModelForm):
CATEGORY_CHOICES = []
categories = Category.objects.all()
for category in categories:
CATEGORY_CHOICES.append((category.id, capwords(category.title)))
title = forms.CharField(
required = True,
widget = forms.TextInput(attrs = {'class': 'form-control ', 'placeholder': 'e.g Software Engineer'}),
)
category = forms.ChoiceField(
choices = CATEGORY_CHOICES,
required = True,
widget = forms.Select(attrs = {'class': 'selectpicker border rounded', 'placeholder': 'select category'}),
)
class Meta:
model = Jobs
fields = [
"title",
"category",
]
models.py
class Category(models.Model):
title = models.CharField(max_length= 200, null = True, blank = True)
description = models.TextField(null = True, blank = True)
uniqueId = models.CharField(null = True, blank = True, max_length = 100)
categoryImage = models.ImageField(default = 'category.png', upload_to = 'upload_images')
slug = models.SlugField(max_length = 500, unique=True, blank = True, null = True)
class Meta:
verbose_name_plural = "Categories"
class Jobs(models.Model):
title = models.CharField(max_length=1000, null = True, blank = True)
company = models.ForeignKey(Company, on_delete = models.CASCADE, null = True, blank = True)
category = models.ForeignKey(Category, related_name= 'Category', on_delete = models.CASCADE, null = True, blank = True)
location = models.CharField(max_length=1000, null = True, blank = True)
salary = models.CharField(max_length=1000, null = True, blank = True)
uniqueId = models.CharField(null = True, blank = True, max_length = 100)
nature = models.CharField(max_length=100, choices=TYPE_CHOICES, default=NOT_PROVIDED)
experience = models.CharField(max_length=100, choices=EXP_CHOICES, default=NOT_PROVIDED)
summary = models.TextField(null = True, blank = True)
description = models.TextField(null = True, blank = True)
closing_date = models.DateField(blank = True, null = True)
date_posted = models.DateField(blank = True, null = True)
contract_type = models.CharField(max_length = 1000, null = True, blank = True)
date_created = models.DateTimeField(default = timezone.now)
slug = models.SlugField(max_length = 1000, unique = True, blank = True, null = True)
def __str__(self):
return '{} - {}'.format(self.company, self.title)
def get_absolute_url(self):
return reverse('job-detail', kwargs = {'slug': self.slug})
class Meta:
verbose_name_plural = "Jobs"
views.py
def add_job(request):
if request.method == 'POST':
form = JobForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.user = request.user
obj.save()
messages.success(request, 'Job added Successfully')
return redirect('add-job')
else:
messages.error(request, 'Error Processing Your Request')
context = {'form': form}
return render(request, 'index.html', context)
else:
form = JobForm()
context = {'form': form}
return render(request, 'add-job.html', context)
CodePudding user response:
The job object expects the category to be an instance of the Category
model, because it has a ForeignKey relationship defined to it. Just use a ModelChoiceField
instead of the ChoiceField
in the form.
class JobForm(forms.ModelForm):
title = forms.CharField(
required=True,
widget=forms.TextInput(attrs={'class': 'form-control ', 'placeholder': 'e.g Software Engineer'}),
)
category = forms.ModelChoiceField(queryset=Category.objects.all(),
required=True)
class Meta:
model = Jobs
fields = [
"title",
"category",
]
CodePudding user response:
Helge's answer here explains the problem.
Quite often, its best to create relational fields indirectly rather than via a ModelForm or ModelChoiceField. Instead you add some non-relational (character, numeric, date etc) form fields and process these to identify the relevant relation. The code outline will then look something like:
if form.is_valid(): # or subclass the form_valid method of a Class based view
info1 = form.cleaned_data['info1'] # your added model fields
info2 = form.cleaned_data['info2']
# process info1 and info2 to identify the relevant object(s) needed
# for the relation
if( there_is_a_problem):
form.add_error('info1', 'explain the problem')
# the form is now invalid. In a class-based view you can do
return self.form_invalid( form)
instance = form.save( commit=False)
instance.relation = # what you worked out above
instance.save()