除非选中,否则带有BooleanField的Django表单始终无效

时间:2011-12-17 05:34:35

标签: django django-forms

我有一个使用以下形式的应用程序:

class ConfirmForm(forms.Form):
    account_name = forms.CharField(widget=forms.HiddenInput)
    up_to_date = forms.BooleanField(initial=True)

我使用以下模板exerpt中的表单:

<form class="confirmform" action="/foo/" enctype="multipart/form-data" method="post">
{{ confirm_form.up_to_date }} Check if this data brings the account up to date.<br>
{{ confirm_form.account_name }} <input type="submit" name="confirm" value="Confirm" />
</form>

我的观点使用以下基本代码结构:

if request.method == 'POST':
    #check for 'confirm' because I actually have multiple forms in this page
    if 'confirm' in request.POST:
        confirm_form = ConfirmForm(request.POST)
        if confirm_form.is_valid():
            #do stuff
        else:
            c['confirm_form'] = confirm_form
else:
    c['confirm_form'] = ConfirmForm({'account_name':'provided_value'})

有两件事是错的:

1)即使我有initial = True,当页面加载

时,也会取消选中该复选框

2)除非选中复选框,否则表格始终无效。它仅为up_to_date提供错误:“此字段是必需的。”

我已阅读this similar question,但他的解决方案不适用于我的项目。

那么......发生了什么事?

修改

我更新了上面的代码,以便更忠实于我的实际代码。

问题#1是我的错,因为我在实例化表单时通过绑定数据来覆盖初始值。

问题#2我仍然考虑一个问题。在required=False上使用up_to_date可以解决问题,但是使用默认小部件似乎不正确,BooleanField可以是NULL(导致有效性检查失败) )或True但从不False

6 个答案:

答案 0 :(得分:35)

initial=True应该使用checked="checked"呈现窗口小部件,因此我没有看到问题..但窗体无效的原因是默认情况下所有字段都是必需的,除非您另行指定。

  

Field.required¶默认情况下,每个Field类都假设值为   必需的,所以如果你传递一个空值 - 无或空   string(“”) - 然后clean()将引发ValidationError异常:

如果您希望复选框或任何其他值是可选的,则需要将required=False传递到表单字段构造函数中。

up_to_date = forms.BooleanField(initial=True, required=False) 
# no longer required..

答案 1 :(得分:30)

在Django表单中,必须使用required=False创建布尔字段。

如果未选中该复选框,则浏览器不会在请求的POST参数中发送该字段。如果没有指定该字段是可选的,Django会在不在POST参数中时将其视为缺少的字段。

Imho,对于布尔表单字段,Django默认具有此行为会很好..

(Yuji在评论中已经回答了这个问题,但它可以作为答案)

答案 2 :(得分:12)

根据official docs

  

如果您希望在表单中包含可以是TrueFalse的布尔值(例如选中或未选中复选框),则必须记住传入 {{1} 时创建BooleanField。

答案 3 :(得分:0)

确保在第一次加载页面时不覆盖初始表单。

我最初没有检查请求中是否有任何内容.GET。页面第一次加载request.GET为None,调用SomeForm(request.GET)实际上会清除初始值。

def some_view(request):

    form = SomeForm()

    if request.method == 'GET':
        form = SomeForm(request.GET)

添加支票以确保请求中有内容.GET已修复此问题。

def some_view(request):

    form = SomeForm()

    if request.method == 'GET' and request.GET:
        form = SomeForm(request.GET)

答案 4 :(得分:0)

如果按照建议进行操作,则您的 up_to_date 字段可能始终为False。而且您永远不会知道这是因为用户还是想要这样,因为用户跳过了该字段

我在法律上要求使用OPT_IN问题时也遇到了同样的问题。在哪里进行注册,我需要让用户做出良心决定,以允许我的系统向其发送未经请求的电子邮件(或不向他们发送)。我正在使用Django-Allauth和自定义用户数据库。

我将在下面分享我的解决方案,希望您可以适应您的情况-我改编自the DOCS

forms.py:

# ExtraFieldsSignup as per https://stackoverflow.com/a/12308807
class SignupFormExtraFields(forms.Form):
  CHOICES = (('1', 'YES, keep in touch',), ('2', 'No',))
  first_name = forms.CharField(max_length=30, label='Voornaam')
  last_name = forms.CharField(max_length=30, label='Achternaam')
  opt_in = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)

  def signup(self, request, user):
    user.first_name = self.cleaned_data['first_name']
    user.last_name = self.cleaned_data['last_name']
    # Now we figure out what the user chose:
    if self.cleaned_data['opt_in'] == '1':
        user.opt_in = True
    else:
        user.opt_in = False
    user.save()

答案 5 :(得分:0)

只是预感,但这可能只是基本知识-花费了几个小时才意识到与基本变量类型类似的东西。

就我而言,创建表格后(非常基本,请参见下文)

class para_selection(forms.Form):
    first=forms.BooleanField(initial=False, required=False)
    second=forms.BooleanField(initial=False, required=False)
    third=forms.BooleanField(initial=False, required=False)
    fourth=forms.BooleanField(initial=False, required=False)

...我正在使用     如果选择=='真': .. 在我看来。但是由于表单使用的是布尔值,因此正确的代码应为:     如果选择为True:

第一行将永远无法工作,因为布尔型不使用“ ==”。希望情况并非如此,但由于我一直在Internet上进行尝试和搜索,而不关注我使用的变量类型,因此想在这里进行标记。