Django, save ModelForm

Question:

I have created a model Student which extends from the Django User and is a foreign key to another model while it has an integer field called year. What i’m trying to do is to save a form, which has 2 fields. The one is the course id and the another one is the the integer field year. When I’m clicking submit, i’m getting an error Cannot assign “u’2′”: “Student.course” must be a “Course” instance.

models.py

class Student(models.Model):
    user = models.OneToOneField(User)
    course = models.ForeignKey(Course)
    year = models.IntegerField(validators=[MinValueValidator(1),
                                           MaxValueValidator(7)])

view.py

def step3(request):
    user = request.user
    if request.method == 'POST':
        form = SelectCourseYear(request.POST)
        if form.is_valid():
            form.save()
            return render_to_response("registration/complete.html", RequestContext(request))
    else:
        form = SelectCourseYear()
    return render(request, 'registration/step3.html',)

forms.py

class SelectCourseYear(forms.ModelForm):
    course = forms.CharField()
    year = forms.IntegerField(required=True)

    class Meta:
        model = Student
        fields = ['user', 'course', 'year']
Asked By: manosim

||

Answers:

course has to be an instance of a Course model, not just the primary key of the instance. You can still accept an id in the form as a text input, but you’re going to need to retrieve the actual course instance and assign the value.

You’ll need to verify that the course id is valid, so putting that code into the clean method isn’t a bad idea. Notice also how the course field is excluded here? Otherwise the form will expect it to be present. You also don’t need to re-define the year field, as the ModelForm will inherit that field from the Student model.

# forms.py

class SelectCourseYear(forms.ModelForm):
    class Meta:
        model = Student
        exclude = ['user', 'course']

    course_id = forms.IntegerField()

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user')
        super(SelectCourseYear, self).__init__(*args, **kwargs)

    def clean_course_id(self):
        course_id = self.cleaned_data.get('course_id')
        try:
            self.course = Course.objects.get(pk=course_id)
        except Course.DoesNotExist:
            raise forms.ValidationError('Sorry, that course id is not valid.')

        return course_id

    def save(self, commit=True):
        instance = super(SelectCourseYear, self).save(commit=False)
        instance.course = self.course
        instance.user = self.user
        if commit:
            instance.save()
        return instance


# views.py

def step3(request):
    if request.method == 'POST':
        form = SelectCourseYear(request.POST or None, user=request.user)
        if form.is_valid():
            form.save()
            return render_to_response("registration/complete.html",
                RequestContext(request))
    return render(request, 'registration/step3.html',)

Now, when you call .save() on the model, the course field will be assigned an instance of Course

Answered By: Brandon Taylor

You dont need to redefine fields in the ModelForm if you’ve already mentioned them in the fields attribute. So your form should look like this –

class SelectCourseYear(forms.ModelForm):
    class Meta:
        model = Student
        fields = ['course', 'year'] # removing user. we'll handle that in view

And we can handle the form with ease in the view –

def step3(request):
    user = request.user
    if request.method == 'POST':
        form = SelectCourseYear(request.POST)
        if form.is_valid():
            student = form.save(commit=False)
            # commit=False tells Django that "Don't send this to database yet.
            # I have more things I want to do with it."

            student.user = request.user # Set the user object here
            student.save() # Now you can send it to DB

            return render_to_response("registration/complete.html", RequestContext(request))
    else:
        form = SelectCourseYear()
    return render(request, 'registration/step3.html',)
Answered By: Bibhas Debnath
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.