Search code examples
pythondjangodjango-1.9

Django: Set initial value for ForiegnKey in a CreateView


I'm trying to create a view of type CreateView. This view will take the form_class = CourseForm that I created and excluded some fields in it. The instructor field is a foriegnKey and I don't want the user to be able to control it in the form. It's a field that depends on the signed in user.

# forms.py
class CourseForm(forms.ModelForm):
    class Meta:
        model = Course
        exclude = ['instructor', 'members', 'slug']
    # ...

my view is as follows. I thought that by including the instructor value in initial would pass the profile instance when I submit

# views.py

@method_decorator(login_required, name='dispatch')
class CourseCreateView(CreateView):
    model = Course
    template_name = 'course_form.html'
    success_url = reverse_lazy('course-create-complete')

    form_class = CourseForm

    def get_initial(self):
        initial = super(CourseCreateView, self).get_initial()
        initial = initial.copy()
        profile = get_object_or_404(Profile, user__username=self.request.user)
        initial['instructor'] = profile
        return initial


# models.py

class Course(models.Model):
    instructor = models.ForeignKey(Profile, related_name="Instructor")
    # ... other fields

but the probelm is that whenever I submit the form I get the following error:

NOT NULL constraint failed: myapp_course.instructor_id


Solution

  • If you want to set the initial value of instructor field, you shouldn't exclude it from the form. You could instead make the field hidden.

    Or you could include that in the exclude list, but then you shouldn't override get_initial method, but do the assignment manually:

    class CourseCreateView(CreateView):
        def form_valid(self, form):
            self.object = form.save(commit=False)
            # create instructor based on self.request.user
            self.object.instructor = instructor
            self.object.save()
        return HttpResponseRedirect(self.get_success_url())
    

    Check django doc about what does save(commit=False) do.

    Also check django doc about form_valid function and how forms are handled in class based views.