重新显示表单,其中包含有关Django错误的先前提交的数据

时间:2015-01-14 20:03:46

标签: html django forms

如何在遇到错误后让提交的数据在formset中重新显示? Django的书谈到了这一点,我能够使它以一种形式工作,但不是在一个表格中。

方案: 有2个必填字段 - 名字和姓氏。如果我只在名字字段中输入“John”,将姓氏字段留空,然后单击“提交”,我将收到一条错误消息,说明这两个字段都是必填字段,表单会清除提交的数据并显示错误消息。我想在名字字段中看到名称“John”以及错误消息。

非常感谢!

**forms.py**

from django import forms
from django.forms.formsets import BaseFormSet


class NameForm (forms.Form):

    first_name = forms.CharField (max_length = 20, required = False)
    last_name = forms.CharField (max_length = 20, required = False)


class BaseNameFormSet (BaseFormSet):

    def clean (self):
        if any (self.errors):
            return

        firstnames = []
        lastnames = []
        for form in self.forms:
            firstname = form.cleaned_data.get ('first_name')
            lastname = form.cleaned_data.get ('last_name')

            if (firstname in firstnames) or (lastname in lastnames):
                raise forms.ValidationError ('First or last name must be unique')
            if (firstname == '') or (lastname == ''):
                raise forms.ValidationError ('Both first and last name must be filled out')

            firstnames.append (firstname)
            lastnames.append (lastname)

        return self.cleaned_data


**views.py**

from django.shortcuts import render
from django.forms.formsets import formset_factory
from nameform.forms import NameForm
from nameform.forms import BaseNameFormSet
from nameform.addName import webform


# Create your views here.
def addname (request):

    # Set maximum to avoid default of 1000 forms.
    NameFormSet = formset_factory (NameForm, formset = BaseNameFormSet, extra = 2, max_num = 5)

    if request.method == 'POST':
        # Django will become valid even if an empty form is submitted. Adding initial data causes unbound form and
        # trigger formset.errors
        # formset = NameFormSet (request.POST, initial = [{'first_name': 'John', 'last_name': 'Doe'}])
        formset = NameFormSet (request.POST)

        if formset.is_valid ():
            location = request.POST ['site']
            data = formset.cleaned_data

            for form in data:
                # Retrieving the value in an empty dictionary will result key error as it doesn't exist
                # firstname = form ['first_name']
                # lastname = form ['last_name']

                firstname = form.get ('first_name')
                lastname = form.get ('last_name')

                if firstname and lastname:
                    webform (firstname, lastname, location)

            context = {'data': data, 'location': location}

            return render (request, 'nameform/success.html', context)

    else:
        formset = NameFormSet ()

    return render (request, 'nameform/addname.html', {
        'formset': formset,
        'first_name': request.POST.get ('first_name', ''),
        'last_name': request.POST.get ('last_name', '')
    })


**addname.html**

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Add Name</title>
</head>
<body>
    <h1>Add Name</h1>
    <form action="" method="POST">{% csrf_token %}
        <h3>Location:</h3>
        <p><input type="radio" id="radio1" name="site" value="Location_A" checked>
        <label for="radio1">Location A</label>
        <input type="radio" id="radio2" name="site" value="Location_B">
        <label for="radio2">Location B</label></p>
        {{ formset.management_form }}
        <label for="id_form-0-first_name">First Name:</label>
        <input id="id_form-0-first_name" maxlength="20" name="form-0-first_name" type="text" value="{{ first_name }}" />
        <label for="id_form-0-last_name">Last Name:</label>
        <input id="id_form-0-last_name" maxlength="20" name="form-0-last_name" type="text" value="{{ last_name }}" />
        <p><label for="id_form-1-first_name">First Name:</label>
        <input id="id_form-1-first_name" maxlength="20" name="form-1-first_name" type="text" value="{{ first_name }}" />
        <label for="id_form-1-last_name">Last Name:</label>
        <input id="id_form-1-last_name" maxlength="20" name="form-1-last_name" type="text" value="{{ last_name }}" /></p>
        <p><input type="submit" value="Add Name"></p>
    </form>

    {% if formset.errors %}
    <p style="color: red;">Please correct the error below:</p>
    {{ formset.non_form_errors }}
    {% endif %}

</body>
</html>

Form

在Shell中:

>>> partial_data = {
...     'form-TOTAL_FORMS': '2',
...     'form-INITIAL_FORMS': '0',
...     'form-MAX_NUM_FORMS': '3',
...     'form-0-first_name': 'John',
...     'form-0-last_name': 'Doe',
...     'form-1-first_name': 'James',
...     'form-1-last_name': ''
... }
>>> 
>>> NameFormSet = formset_factory (NameForm, formset = BaseNameFormSet)
>>> formset = NameFormSet (partial_data)
>>> 
>>> formset.is_valid ()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors ()
['Both first and last name must be filled out']

2 个答案:

答案 0 :(得分:0)

formset与表单完全相同,只需将其加载到request.POST。

这是我的一个项目中的一些代码。

formset = modelformset_factory(PaymentTemplates, extra=extras, form=PaymentTemplateForm)
    if request.POST:
        formset = formset(request.POST)

在你的模板中:

{% if formset.total_error_count %}
    <ul class="errorList">
    {% for dict in formset.errors %}
        {% for error in dict.values %}
        <li>{{ error }}</li>
        {% endfor %}
    {% endfor %}
    </ul>
{% endif %}

我假设你也知道你需要这个:

<form action="..." method="POST">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
    {{ form.as_table }}
{% endfor %}
</form>

查看如何手动渲染表单, 或者使用像crispy forms这样的东西,或者使用django-bootstrap3来处理所有这些。

答案 1 :(得分:0)

事实证明,我需要在下面进行更改。这里的关键是将“first_name_0”变量与html中的输入字段“form-0-first_name”相关联。如果同时使变量和html输入框的名称相同,则会出现错误。

例如:

return render (request, 'nameform/addname.html', {
        'formset': formset,
        'form-0-first_name': request.POST.get ('form-0-first_name', '')})

Django不喜欢那种格式。而是使它与我在下面的内容相同,以匹配哪个输入字段与变量。

<强> views.py

...
...
...
    return render (request, 'nameform/addname.html', {
        'formset': formset,
        'first_name_0': request.POST.get ('form-0-first_name', ''),
        'last_name_0': request.POST.get ('form-0-last_name', ''),
        'first_name_1': request.POST.get ('form-1-first_name', ''),
        'last_name_1': request.POST.get ('form-1-last_name', '')

<强> addname.hmtl

   ...
    ...
    ...
    {{ formset.management_form }}
            <label for="id_form-0-first_name">First Name:</label>
            <input id="id_form-0-first_name" maxlength="20" name="form-0-first_name" type="text" value="{{ first_name_0 }}" />
            <label for="id_form-0-last_name">Last Name:</label>
            <input id="id_form-0-last_name" maxlength="20" name="form-0-last_name" type="text" value="{{ last_name_0 }}" />
            <p><label for="id_form-1-first_name">First Name:</label>
            <input id="id_form-1-first_name" maxlength="20" name="form-1-first_name" type="text" value="{{ first_name_1 }}" />
            <label for="id_form-1-last_name">Last Name:</label>
            <input id="id_form-1-last_name" maxlength="20" name="form-1-last_name" type="text" value="{{ last_name_1 }}" /></p>

所需的结果:

现在,用户可以在不重新填写整个表单的情况下知道他们做错了什么或丢失了什么。

Add_Name