'Is it possible to use/test a value of Django's BooleanField without a model?

I'm trying to make a workflow where the user enters data on one page, then has to check the data and tick a tickbox to accept the T&C's. So the code has to check that the checkbox is checked before going on, but doesn't care until the second step.

It's not a bound field and I think that's the problem - I don't need a model just to handle a workflow, and I don't want to have to store, in a database, a simple ephemeral field in a form!

I'm running Django 2.1.5.

I've tried every possible combination of:

  • test_form.fields['tickbox'].value - doesn't exist, which is ridiculous
  • test_form.fields['tickbox'] == False - value doesn't change at all
  • request.POST['tickbox'] seems to go missing?

views.py

from django.http import HttpResponse
from django.template import loader
from django.forms import Form, CharField, BooleanField

class test_form(Form):
    name = CharField()
    tickbox = BooleanField(required=False, initial=False)

def testview(request):
    if request.method == 'POST':
        testform = test_form(request.POST)
        if testform.fields['tickbox'] == True:
            do_things()
        else:
            dont_do_things()
    else:
        testform = test_form()
    template = loader.get_template('testform.html')

    context = { 'testform : userform, 
                }
    return HttpResponse(template.render(context, request))

I should be able to test the value of the field and get a changing response depending on if the user has ticked the box or not - I seem to get True regardless?



Solution 1:[1]

Here is a way how to solve your issue using Class Based Views and Function Based Views:

So, first:

forms.py:

from django import forms

class CheckboxForm(forms.Form):
    name = forms.CharField()
    tickbox = forms.BooleanField(required=False, initial=False)

    def clean_tickbox(self):
        '''Here we can check if the checkbox is checked or not'''
        tickbox = self.cleaned_data.get('tickbox')
        if not tickbox:
            # Raise an error if the checkbox is not checked
            raise forms.ValidationError("You must select this option")
        # And return the value
        return tickbox

With a class based view:

views.py:

from django.views import View
from django.contrib import messages

class CheckboxView(View):
    template_name = 'checkbox.html'
    form_class = forms.CheckboxForm

    def get(self, request, *args, **kwargs):
        form = self.form_class()
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        # check if the form is valid
        if form.is_valid():
            # Use Django builtin messages framework
            messages.success(request, "Checked!")
        else:
            messages.error(request, "not checked!")

        return render(request, self.template_name, {'form': form})

With function based views:

from django.contrib import messages

def checkbox_func(request, *args, **kwargs):
    template = 'checkbox.html'
    if request.method == 'POST':
        form = forms.CheckboxForm(request.POST)
        # Check if the form is valid
        if form.is_valid():
            messages.success(request, "Checked!")
        else:
            messages.error(request, "Not checked!")
    else:
        form = forms.CheckboxForm()

    return render(request, template, {'form': form})

urls.py:

from django.urls import path
from YOUR_APP import views

urlpatterns = [
    # ... Your URLS
    # Class Based Views
    path('checkbox/', views.CheckboxView.as_view(), name="checkbox"),
    # Function Based Views
    path('checkbox2/', views.checkbox_func, name="checkbox_v2")
]

And your template: checkbox.html:

{% for message in messages %}
    {{message}}
{% endfor %}

<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Submit</button>
</form>

Demo:

1 2 3 4 5 6

Solution 2:[2]

First of all, yes it is perfectly possible to have FormFields without them being declared in a Model.

You seem to be trying to do form validation on your own when django already handles simple cases like this for you. Let's start by looking at the documentation of BooleanField:

  • Validates that the value is True (e.g. the check box is checked) if the field has required=True

Since that is exactly what you want to validate we can change the field definition:

tickbox = BooleanField(required=True, initial=False)

Since the documentation told us that django takes care of validating that the checkbox is actually checked there is no need for the custom validation code anymore. Let's look at the view next and refactor it:

def testview(request):
    if request.method == 'POST':
        testform = test_form(request.POST)

        # check if the form is valid (that includes the checkbox being checked)
        if testform.is_valid():
            do_things()
        else:
            dont_do_things()
    else:
        testform = test_form()
    template = loader.get_template('testform.html')

    context = {'testform': userform} # added a closing single tick
    return HttpResponse(template.render(context, request))

So instead of doing custom validation you just call the .is_valid() method of your Form instance to run validation. If you want to access any of the fields instead of using testform.fields[fieldname] you'd do testform.cleaned_data[fieldname] which only accesses fields that have been validated.

For more information on form processing in general I highly recommend reading through django's Working with forms.

Solution 3:[3]

I simply use the "cleaned_data" to check if the field is not part of the model but its just a form field.

so in your case this will be in your view

if testform.cleaned_data['tickbox'] == True:
            do_things()
        else:
            dont_do_things()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chiheb Nexus
Solution 2 Fynn Becker
Solution 3 Vivek Amirthakadeswaran