如何在 Django 中验证表单集

How to validate a formset in dajngo

我正在使用 formset 将我的数据输入到数据库中,但出于某种原因,每当我在终端中测试并调用 .is_valid() 时,它就无法验证,它只是 returns false 无论我尝试什么。这是我的 views.py 和 forms.py 中的代码。任何帮助将不胜感激!

# Advanced Subjects (Advanced Biology)
def form_5_entry_biology_view(self, request):
    current_teacher = User.objects.get(email=request.user.email)
    logged_school = current_teacher.school_number
    students_involved = User.objects.get(school_number=logged_school).teacher.all()
    data = {"student_name": students_involved}
    formset_data = AdvancedStudents.objects.filter(class_studying="Form V", combination="PCB")
    student_formset = formset_factory(AdvancedBiologyForm, extra=0)
    initial = []
    for element in formset_data:
        initial.append({"student_name": element})
    formset = student_formset(request.POST or None, initial=initial)
    print(formset.is_valid())
    context = {
        "students": students_involved,
        "formset": formset,
        "class_of_students": "Form V",
        "subject_name": "Advanced Biology",
    }
    return render(request, "analyzer/marks_entry/marks_entry_page.html", context)

这是我的 forms.py

class AdvancedBiologyForm(forms.ModelForm):
    student_name = forms.CharField()

    class Meta:
        model = ResultsALevel
        fields = ('student_name', 'advanced_biology_1', 'advanced_biology_2', 
                   'advanced_biology_3',)

在使用 request.POSTis_valid() 之前,您可能需要检查是否确实存在 post 请求或是否刚刚查看了该页面:

def form_5_entry_biology_view(self, request):
    current_teacher = User.objects.get(email=request.user.email)
    logged_school = current_teacher.school_number
    students_involved = User.objects.get(school_number=logged_school).teacher.all()
    data = {"student_name": students_involved}
    formset_data = AdvancedStudents.objects.filter(class_studying="Form V", combination="PCB")

    # Here you are creating the formset using the model
    student_formset = formset_factory(AdvancedBiologyForm, extra=0)

    # Here you are generating your initial data
    initial = []
    for element in formset_data:
        initial.append({"student_name": element})

    # Here you are using the initial data to create pre-populated
    # forms with it using the formset.
    # These forms will be displayed when the page loads.
    formset = student_formset(initial=initial)

    context = {
        "students": students_involved,
        "formset": formset,
        "class_of_students": "Form V",
        "subject_name": "Advanced Biology",
    }

    # But if the user hits the "submit"-Button...
    if request.method == 'POST':
        # ... you don't want to have the formset with your
        # initial data. Instead you want the entries by the user
        # which are transmitted in request.POST to populate the
        # formset forms.
        formset = student_formset(request.POST or None)
        # Now you can validate the formset with the fields which
        # got input the the user; not the "initial" data like in
        # your original code
        if formset.is_valid():
            # This runs formset validation.
            # You can define your own formset validations like
            # you would for models/forms.
            for form in formset:
                # And / Alternatively:
                # you could in theory also add another "if form.is_valid():" in here
                # This would trigger any validation on the
                # model/form; not the validators on the formset.
                form.save()
            return HttpResponseRedirect(...
    return render(request, "analyzer/marks_entry/marks_entry_page.html", context)

否则您可能会在未绑定的表单上调用 is_valid()。 来自 Django docs:

If the form is submitted using a POST request, the view will once again create a form instance and populate it with data from the request: form = NameForm(request.POST) This is called “binding data to the form” (it is now a bound form).

基本上,如果一个表单是空的,它就是未绑定的,如果它填充了数据,它就会在 POST 之后绑定。当你打开一个页面并立即尝试“is_valid()”时,它基本上总是错误的,因为你正在检查一个空表单是否有效;它可能永远不会。

指出错误:

formset = student_formset(request.POST or None, initial=initial)
print(formset.is_valid())

这是无效的。因为初始值不等于用“真实”值填充表单字段。因此,它会尝试用 request.POST or None 填充表单中的字段。 但是您没有 if request.method == 'POST': 条件。因此,您的代码将 运行 通过,然后到达最后一行代码,即显示页面的 return 语句。 这意味着您的代码甚至在用户看到页面之前就验证了 request.POST or None。因此,用户不可能已经输入数据并点击提交。这意味着没有 POST-请求,所以它总是变成 None。因此,您基本上是在一个没有字段值的表单上调用 is_valid(),这会导致验证失败。

编辑 1:我刚注意到你的 forms.py 你写了:

fields = ('student_name', 'advanced_biology_1', 'advanced_biology_2', 
                   'advanced_biology_3',)

这个should be a list改为:

fields = ['student_name', 'advanced_biology_1', 'advanced_biology_2', 
                   'advanced_biology_3',]

编辑 2:修复了错误的变量名 编辑 3:添加了广泛的评论以阐明代码中发生的事情 编辑 4:更清楚地指出问题的原因。