Django,保存ModelForm

33 投票
2 回答
72297 浏览
提问于 2025-04-18 00:31

我创建了一个叫Student的模型,它是从Django User扩展而来的,并且它还关联了另一个模型,里面有一个叫做year的整数字段。我现在想做的是保存一个表单,这个表单有两个字段,一个是课程ID,另一个就是那个整数字段year。但是当我点击提交的时候,出现了一个错误:无法分配 "u'2'": "Student.course" 必须是一个 "Course" 实例。

这是我的模型文件 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']

2 个回答

8

course 必须是一个课程模型的实例,而不仅仅是这个实例的主键。你可以在表单中接受一个文本输入的 id,但你需要去获取实际的课程实例并把这个值赋给它。

你需要确认课程的 id 是有效的,所以把这段代码放在清理方法里是个不错的主意。还有注意到这里的 course 字段被排除了吧?否则表单会期待这个字段的存在。你也不需要重新定义年份字段,因为 ModelForm 会从学生模型中继承这个字段。

# 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',)

现在,当你在模型上调用 .save() 时,课程字段会被赋值为一个 Course 的实例。

63

如果你已经在fields属性里提到过字段,就不需要在ModelForm里重新定义这些字段。所以你的表单应该是这样的 -

class SelectCourseYear(forms.ModelForm):
    class Meta:
        model = Student
        fields = ['course', 'year'] # removing user. we'll handle that in 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',)

撰写回答