如何获取模型表单的实例并将其分配给视图中的键?
how to get instance of a model form and assign it to its key in view?
在表单处理期间,当用户从下拉列表中选择一个值时,我希望能够在其基础模型的模型对象上设置外键字段。
models.py
class Question(models.Model):
question = models.CharField(max_length=200)
class Teacher(models.Model):
name = models.CharField(max_length=200)
l_name = models.CharField(max_length=200)
class Student_Answer(models.Model):
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.SmallIntegerField(choices=RATING_CHOICES)
例如,我在模型A中有五个记录,在模型B中有两个记录,并且我有两个模型表单。
forms.py
class AnswerForm(ModelForm):
class Meta:
model = Student_Answer
fields = ('answer',)
widgets = { 'answer': RadioSelect(choices=RATING_CHOICES),}
class TeacherForm(ModelForm):
name = ModelChoiceField(queryset=Teacher.objects.all())
class Meta:
model = Teacher
fields = ('name',)
对于问题,我只是直接在视图中分配它们,然后在验证后将实例交给外键。现在,如果我对 Teacher 做同样的事情,我的意思是 teacher = Teacher.objects.get(id=2) 然后 choice.teacher = teacher 它会完美地工作。但这不是我想要的。教师将由用户选择。我正在寻找类似下面视图的方式。
views.py
def index(request):
question1 = Question.objects.get(id=6)
question2 = Question.objects.get(id=7)
if request.method == "POST":
teacher_form = TeacherForm(request.POST)
form = AnswerForm(request.POST, prefix='question1')
form1 = AnswerForm(request.POST, prefix='question2')
if (form.is_valid):
choice = form.save(commit=False)
choice.question = question1
choice.teacher = teacher_form
choice.save()
choice = form1.save(commit=False)
choice.teacher = teacher_form
choice.question = question2
choice.save()
return HttpResponseRedirect('/submited/')
else:
teacher_form = TeacherForm()
form = AnswerForm(prefix='question1')
form1 = AnswerForm(prefix='question2')
context = {
'teacher_form': teacher_form,
'form': form,
'form1': form1,
'all_questions': Question.objects.all(),
}
return render(request, 'index.html', context)
上面例子的问题是这个错误:
ValueError: Cannot assign "<TeacherForm bound=True, valid=Unknown, fields=(name)>": "Student_Answer.teacher" must be a "Teacher" instance.
如果我包含实例 choice.teacher = teacher_form.instance 那么就会出现这个错误:
Exception Value:
save() prohibited to prevent data loss due to unsaved related object 'teacher'.
如果我在验证后将表格保存在第一行,它将为教师创建一条新记录 class。我不想保存新记录,我只想将所选值存储在模板中并将该值存储为 Student_Answer class。有办法解决这个问题吗?
index.html
<form action="{% url 'evaluation:index'%}" method="POST">
{% csrf_token %}
{{ teacher_form }}
{{ all_questions.0 }}
{{ form }}
{{ all_questions.1}}
{{ form1 }}
<input type="submit" value="Vote">
</form>
首先-您的观点存在严重问题。您正在使用多种形式(这并不罕见且很有可能)但您只验证了一个 - 但您必须验证所有这些。有一篇关于这样做的好文章,如果我找到它,我会在更新中 link 它。
您的第二个错误正是因为它而出现 - 您试图从未经验证的表单设置实例。
if all([form.is_valid(), form1.is_valid(), teacher_form.is_valid()]):
其次,是的,您不想 save() 那个教师表格,您甚至不需要它是一个 ModelForm,只需 forms.Form 和 ModelChoiceField 就可以了。您只需要验证它然后访问它的 cleaned_data
# I'm renaming field to 'teacher' since 'name' is poor choice for Teacher object
teacher = teacher_form.cleaned_data['teacher']
最后,对于一些问题形式,您可能需要一个模型形式集 (2-3) 常量形式可能适用于当前方法,但更多或不同数量的问题会让人非常烦恼。
表单集:https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/#model-formsets
在表单处理期间,当用户从下拉列表中选择一个值时,我希望能够在其基础模型的模型对象上设置外键字段。
models.py
class Question(models.Model):
question = models.CharField(max_length=200)
class Teacher(models.Model):
name = models.CharField(max_length=200)
l_name = models.CharField(max_length=200)
class Student_Answer(models.Model):
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.SmallIntegerField(choices=RATING_CHOICES)
例如,我在模型A中有五个记录,在模型B中有两个记录,并且我有两个模型表单。
forms.py
class AnswerForm(ModelForm):
class Meta:
model = Student_Answer
fields = ('answer',)
widgets = { 'answer': RadioSelect(choices=RATING_CHOICES),}
class TeacherForm(ModelForm):
name = ModelChoiceField(queryset=Teacher.objects.all())
class Meta:
model = Teacher
fields = ('name',)
对于问题,我只是直接在视图中分配它们,然后在验证后将实例交给外键。现在,如果我对 Teacher 做同样的事情,我的意思是 teacher = Teacher.objects.get(id=2) 然后 choice.teacher = teacher 它会完美地工作。但这不是我想要的。教师将由用户选择。我正在寻找类似下面视图的方式。
views.py
def index(request):
question1 = Question.objects.get(id=6)
question2 = Question.objects.get(id=7)
if request.method == "POST":
teacher_form = TeacherForm(request.POST)
form = AnswerForm(request.POST, prefix='question1')
form1 = AnswerForm(request.POST, prefix='question2')
if (form.is_valid):
choice = form.save(commit=False)
choice.question = question1
choice.teacher = teacher_form
choice.save()
choice = form1.save(commit=False)
choice.teacher = teacher_form
choice.question = question2
choice.save()
return HttpResponseRedirect('/submited/')
else:
teacher_form = TeacherForm()
form = AnswerForm(prefix='question1')
form1 = AnswerForm(prefix='question2')
context = {
'teacher_form': teacher_form,
'form': form,
'form1': form1,
'all_questions': Question.objects.all(),
}
return render(request, 'index.html', context)
上面例子的问题是这个错误:
ValueError: Cannot assign "<TeacherForm bound=True, valid=Unknown, fields=(name)>": "Student_Answer.teacher" must be a "Teacher" instance.
如果我包含实例 choice.teacher = teacher_form.instance 那么就会出现这个错误:
Exception Value:
save() prohibited to prevent data loss due to unsaved related object 'teacher'.
如果我在验证后将表格保存在第一行,它将为教师创建一条新记录 class。我不想保存新记录,我只想将所选值存储在模板中并将该值存储为 Student_Answer class。有办法解决这个问题吗?
index.html
<form action="{% url 'evaluation:index'%}" method="POST">
{% csrf_token %}
{{ teacher_form }}
{{ all_questions.0 }}
{{ form }}
{{ all_questions.1}}
{{ form1 }}
<input type="submit" value="Vote">
</form>
首先-您的观点存在严重问题。您正在使用多种形式(这并不罕见且很有可能)但您只验证了一个 - 但您必须验证所有这些。有一篇关于这样做的好文章,如果我找到它,我会在更新中 link 它。 您的第二个错误正是因为它而出现 - 您试图从未经验证的表单设置实例。
if all([form.is_valid(), form1.is_valid(), teacher_form.is_valid()]):
其次,是的,您不想 save() 那个教师表格,您甚至不需要它是一个 ModelForm,只需 forms.Form 和 ModelChoiceField 就可以了。您只需要验证它然后访问它的 cleaned_data
# I'm renaming field to 'teacher' since 'name' is poor choice for Teacher object
teacher = teacher_form.cleaned_data['teacher']
最后,对于一些问题形式,您可能需要一个模型形式集 (2-3) 常量形式可能适用于当前方法,但更多或不同数量的问题会让人非常烦恼。
表单集:https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/#model-formsets