简体   繁体   中英

Django - make a form remember its checkbox values

I'll address this question using a base setup:

# models.py
class MyModel(models.Model):
    required_field = models.CharField("some label", max_length=10)
    another_required_field = models.CharField("some label", max_length=10)
    checkbox = models.BooleanField("some label")

# forms.py
class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

# views.py
class MyView(FormView):
    form_class = MyForm
    template_name = 'some-template.html'

Now suppose I check the checkbox and fill just one of the required fields. The form obviously doesn't pass validation and gets back with errors and all. Problem is, the value of the checkbox comes back unchecked. This is not a big deal with just one BooleanField, but I'm working on a project where I have tons of checkboxes. Check them all from scratch is rather frustrating. So I had a check on django's documentation and stumbled upon this paragraph regarding BooleanFields:

Since all Field subclasses have required=True by default, the validation condition here    
is important. If you want to include a boolean in your form that can be either True or 
False (e.g. a checked or unchecked checkbox), you must remember to pass in 
required=False when creating the BooleanField.

And I did this:

# forms.py
class MyForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        for field in self.fields:
            if isinstance(field, forms.CheckboxInput):
                self.fields[field].required = False
    class Meta:
        model = MyModel

but it didn't work. Again, checkboxes lose their state after the form didn't pass validation, so I guess that was not what I was looking for.

So my question is, is there a way to achieve that? I'm pretty sure there should be one, it would be great if some of you could at least drive me in the right direction. Thanks :-)

EDIT After a bit of debugging, I solved the issue. Turns out I was using a custom template for crispy forms checkboxes, and I found a little bug in there.

Your view would need to populate the form from the request.POST dictionary as such:

def your_view(request):
    form = MyForm(request.POST or None)
    if request.method == 'POST' and form.is_valid():
        form.save()
        # do whatever esle

    return render(request, 'your-template.html', {'form': form})

Unless you pass the request.POST data, and/or an instance of the model you're editing, your form will be un-bound, and therefore not show any values that exist either in the POST data or from your model. If you're editing an instance, it would look like:

def your_view(request, id):
    my_model_instance = MyModel.objects.get(pk=id)
    form = MyForm(request.POST or None, instance=my_model_instance)
    if request.method == 'POST' and form.is_valid():
        form.save()
        # do whatever esle

    return render(request, 'your-template.html', {'form': form})

maybe the problem is on your view:

view exemple:

def view(request):

if request.method == 'POST':#bound the form wit data from request.Post
    form = MyForm(request.POST)

    if form.is_valid():
        #do somthing
        form.save()
    #if form not valid render the page.html with form that  has request.Post data 
    return render(request,'some-template.html',{'form': form})

else:
    form = MyForm()
    return render(request, 'some-template.html',{'form': form})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM