In Django forms, what does a field's required flag actually check, and why does a BooleanField reject an unticked checkbox?
answer
- checked after coercion
- the field's empty_values
- browsers omit unticked boxes
- required means must be ticked
- empty_value per field type
basics
~20 sA Django field with required=True (the default) rejects a cleaned value that is empty: None, '', or an empty list, tuple or dict. An unticked checkbox cleans to False, and a required BooleanField treats False as missing.
solid answer
~40 s`required` defaults to True on every Django form field. After `to_python()` coerces the input, `validate()` raises the `required` error ("This field is required.") if the value is one of the field's empty values: `None`, `''`, `[]`, `()` or `{}`. Because `CharField` strips whitespace first, three spaces count as empty. With `required=False` the field instead cleans empty input to its own empty value: `''` for `CharField` (configurable with `empty_value`), `None` for `DateField` and `IntegerField`, `[]` for `MultipleChoiceField`. Browsers do not submit unticked checkboxes, so `CheckboxInput` reports False, and `BooleanField.validate()` raises `required` for any falsy value. A required `BooleanField` therefore means "must be ticked", which suits a consent box and breaks an optional "partner offers" box unless you set `required=False`.
code
python · 13 linesfrom django import forms
class NewsletterSignupForm(forms.Form):
email = forms.EmailField()
first_name = forms.CharField(required=False, empty_value=None)
accept_privacy = forms.BooleanField() # must be ticked
partner_offers = forms.BooleanField(required=False) # may stay unticked
f = NewsletterSignupForm(data={'email': '[email protected]', 'first_name': ' '})
f.is_valid() # False
f.errors['accept_privacy'] # ['This field is required.']
f.cleaned_data['first_name'] # None
f.cleaned_data['partner_offers'] # Falsego deeper
Recall that fields are required by default, that an unticked checkbox cleans to False, and that a required BooleanField therefore means the box must be ticked.
Explain the order: widget extraction, to_python with stripping, then the empty-values check, and list each field type's empty value, including CharField's empty_value.
Show judgment about data meaning: empty string versus None, the forms.NullBooleanField form field for tri-state answers, and why browser required attributes never replace server checks.
Discuss consistent conventions for optional data across forms and APIs so that blank, absent and false are not conflated in stored records.
## What required checks Every Django form field accepts `required`, and it defaults to **True**. The check happens during field cleaning, after conversion: 1. The widget pulls the raw value out of the submitted data. 2. `to_python()` coerces it. `CharField` with the default `strip=True` trims whitespace here, so `' '` becomes `''`. 3. `validate()` raises a `ValidationError` with code `required` and the message "This field is required." if the value is in the field's **empty values**: `None`, `''`, `[]`, `()` or `{}`. So `required` is not "the key is present in POST"; it is "the coerced value is not empty". A field missing from the submission and a field submitted blank fail the same way. ## What required=False gives you instead An optional field that receives nothing cleans to that field's **empty value** rather than failing: | Field | Empty input cleans to | |---|---| | `CharField`, `EmailField` | `''` (set `empty_value` to change it) | | `IntegerField`, `DateField` | `None` | | `BooleanField` | `False` | | `ChoiceField` | `''` | | `TypedChoiceField` | its `empty_value`, `''` unless set | | `MultipleChoiceField` | `[]` | | `FileField` | `None` | `CharField(required=False, empty_value=None)` is the usual way to tell "left blank" apart in later code when an empty string is ambiguous. The value you get is typed and predictable, so views should read `cleaned_data['first_name']` rather than testing whether a key exists in `request.POST`. ## The checkbox case HTML forms do not send anything for an unticked checkbox. Django's `CheckboxInput.value_from_datadict()` handles that by returning `False` when the name is absent, and it maps the strings `'true'` and `'false'` to booleans. `BooleanField.validate()` then applies its own rule: if the value is falsy **and** the field is required, raise `required`. - For a newsletter's "I agree to the privacy policy" box that rule is exactly right: `forms.BooleanField()` forces the tick. - For "also send me partner offers" it is wrong: the unticked box fails validation. Declare `forms.BooleanField(required=False)` and read `True` or `False` from `cleaned_data`. - For a genuine three-state answer (yes, no, not said) use the form field `forms.NullBooleanField`, whose default widget is a select and whose empty value is `None`. (It is current; only the model field of that name was removed, in Django 4.0, in favour of `BooleanField(null=True)`.) ## What counts as empty, and what does not The generic check compares the coerced value against the empty values only, which has consequences worth knowing: - `0` is **not** empty. A required `IntegerField` accepts `0`; if zero is not a sensible answer, add `min_value=1`. - `False` is not empty for the generic check either. It is `BooleanField`'s own `validate()` that treats a falsy value as missing, which is why the checkbox rule is specific to that field. - A `ChoiceField` whose first option is a placeholder such as `('', 'Choose a frequency')` enforces a real choice through `required`: the placeholder submits `''`, which is empty, so the form reports the required error rather than an invalid choice. - A required `MultipleChoiceField` with nothing selected receives an empty list and fails the same way. ## Browser side versus server side - Because the form's `use_required_attribute` is True by default, required fields also render the HTML `required` attribute. That is a convenience for the user; a crafted POST skips it and the server check still runs. - Error text can be changed per field with `error_messages={'required': '...'}` while keeping the same `required` code. - `required` is a per-field rule. Cross-field rules such as "birthday is required if the subscriber picked the birthday offer" belong in form-level cleaning. ## What interviewers listen for That `required` is checked on the coerced value, that each field type has its own empty value, and that a required `BooleanField` means "must be True". Candidates who have shipped a sign-up form usually remember the partner-offers checkbox that nobody could leave unticked.
- In Django forms, how would you model a subscriber's answer that can be yes, no or not stated?Use `forms.NullBooleanField`. Its default `NullBooleanSelect` widget offers unknown, yes and no, it cleans unrecognised or empty input to `None`, and it never raises the `required` error, so a missing answer is stored as `None` rather than `False`.
- In Django, does removing the HTML required attribute from a rendered field make that field optional?No. The attribute only affects the browser. Server-side cleaning still raises the `required` error while the field's `required` flag is True; to make the field optional you set `required=False` on the field.
saying these in an interview costs you the question
- required=True only checks that the key is present in request.POST.
- An unticked checkbox is submitted as the string 'off'.
- A required BooleanField accepts False as a valid answer.
- Whitespace-only input passes a required CharField.
- Every optional Django form field cleans empty input to None.