【问题标题】:how to get instance of a model form and assign it to its key in view?如何获取模型表单的实例并将其分配给视图中的键?
【发布时间】:2021-01-05 17:34:06
【问题描述】:

在表单处理期间,当用户从下拉列表中选择一个值时,我希望能够在模型对象的基本模型上设置外键字段。

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 中有 5 条记录,在模型 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.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'.

如果我在验证后将表单保存在第一行,它将为教师类创建一个新记录。我不想保存新记录,我只想将所选值存储在模板中并将该值存储给 Student_Answer 类。有没有办法解决这个问题?

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>

【问题讨论】:

    标签: django modelform


    【解决方案1】:

    首先 - 你的观点的一个关键问题。您正在使用几种形式(这并不罕见而且很有可能),但您只验证一个 - 但您必须验证所有这些形式。有一篇关于这样做的好文章,如果我找到它,我会在更新中链接它。 您的第二个错误正是因为它而出现 - 您试图从未经验证的表单设置实例。

     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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多