Use Forms¶
django-enum provides custom form fields and widgets
that make including EnumField and
FlagField fields on forms easy.
Using EnumChoiceField¶
By default Django’s ModelForm will use ChoiceField
to represent EnumField fields. This works great, but if you’re using
an enumeration with symmetric properties or
with custom _missing_() behavior that you would like the form to respect you must
use django-enum’s EnumChoiceField instead. This will happen by
default when using ModelForm forms because field construction is
delegated to formfield().
Tip
See Django’s documentation on how to customize form fields for more detailed instructions on how to alter the default form behavior.
The form fields can be used directly on any form and we can use the configuration parameters to
alter behavior including, modifying the choices list or allowing non-strict values. For example,
using our TextChoicesExample - if color_ext was declared with
strict=False, we could add additional choices and set the form field to any string like so:
from django.forms import Form
from django_enum.forms import EnumChoiceField
class TextChoicesExampleForm(Form):
color = EnumChoiceField(TextChoicesExample.Color)
# since this field is not strict, we can set it to a value not in our
# enum or choice tuple.
color_ext = EnumChoiceField(
TextChoicesExample.Color,
strict=False,
choices=[
('P', 'Purple'),
('O', 'Orange'),
] + TextChoicesExample.Color.choices
)
# when this form is rendered in a template it will include a selected
# option for the value 'Y' that is not part of our Color enumeration.
form = TextChoicesExampleForm(
initial={
"color": TextChoicesExample.Color.RED,
"color_ext": "Y"
}
)
When we render this form using {{ form.as_p }} we get:
<form method="post">
<p>
<label for="id_color">Color:</label>
<select name="color" id="id_color">
<option value="R" selected>Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
</select>
</p>
<p>
<label for="id_color_ext">Color ext:</label>
<select name="color_ext" id="id_color_ext">
<!-- our extended choices -->
<option value="P">Purple</option>
<option value="O">Orange</option>
<!-- choices from our enum -->
<option value="R">Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
<!--
non-strict fields that have data that is not a valid enum value and is
not present in the form field's choices tuple will have that value
rendered as the selected option.
-->
<option value="Y" selected>Y</option>
</select>
</p>
<button type="submit">Submit</button>
</form>
color_ext will validate any string value, but color will raise a
ValidationError if anything other than a valid Color enum is set.
The default widgets used above derive from django.forms.Select. We can also use radio
buttons instead by using django.forms.RadioSelect and
django_enum.forms.NonStrictRadioSelect:
from django.forms import Form, RadioSelect
from django_enum.forms import EnumChoiceField, NonStrictRadioSelect
class TextChoicesExampleForm(Form):
color = EnumChoiceField(TextChoicesExample.Color, widget=RadioSelect)
# since this field is not strict, we can set it to a value not in our
# enum or choice tuple.
color_ext = EnumChoiceField(
TextChoicesExample.Color,
strict=False,
choices=[
('P', 'Purple'),
('O', 'Orange'),
] + TextChoicesExample.Color.choices,
widget=NonStrictRadioSelect
)
# when this form is rendered in a template it will include a selected
# option for the value 'Y' that is not part of our Color enumeration.
form = TextChoicesExampleForm(
initial={
"color": TextChoicesExample.Color.RED,
"color_ext": "Y"
}
)
When we render this form using {{ form.as_p }} we get:
<form method="post">
<p>
<label for="id_color_0">Color:</label>
</p>
<ul id="id_color">
<li>
<label for="id_color_0">
<input type="radio" name="color" value="R" required="" id="id_color_0" checked="">
Red
</label>
</li>
<li>
<label for="id_color_1">
<input type="radio" name="color" value="G" required="" id="id_color_1">
Green
</label>
</li>
<li>
<label for="id_color_2">
<input type="radio" name="color" value="B" required="" id="id_color_2">
Blue
</label>
</li>
</ul>
<p></p>
<p>
<label for="id_color_ext_0">Color ext:</label>
</p>
<ul id="id_color_ext">
<li>
<label for="id_color_ext_0">
<input type="radio" name="color_ext" value="P" required="" id="id_color_ext_0">
Purple
</label>
</li>
<li>
<label for="id_color_ext_1">
<input type="radio" name="color_ext" value="O" required="" id="id_color_ext_1">
Orange
</label>
</li>
<li>
<label for="id_color_ext_2">
<input type="radio" name="color_ext" value="R" required="" id="id_color_ext_2">
Red
</label>
</li>
<li>
<label for="id_color_ext_3">
<input type="radio" name="color_ext" value="G" required="" id="id_color_ext_3">
Green
</label>
</li>
<li>
<label for="id_color_ext_4">
<input type="radio" name="color_ext" value="B" required="" id="id_color_ext_4">
Blue
</label>
</li>
<li>
<label for="id_color_ext_5">
<input type="radio" name="color_ext" value="Y" required="" id="id_color_ext_5" checked="">
Y
</label>
</li>
</ul>
<p></p>
<button type="submit">Submit</button>
</form>
Tip
Have a look at widgets to see all the widgets that are available.
Using EnumFlagField¶
FlagField fields must be rendered with
django_enum.forms.EnumFlagField on forms to work properly. This will happen automatically
for django.forms.ModelForm because it delegates the field creation to
formfield(). This form field type accepts incoming lists of
flags and combines them into composite flag types. The cleaned value is a single flag instance
value, but the interface to world is decomposed.
This example uses the
Permissionsenum from the flags howto.
from django.forms import Form
from django_enum.forms import EnumFlagField
from django_enum import utils
class PermissionsExampleForm(Form):
permissions = EnumFlagField(Group.Permissions)
# form fields can be non-strict just like model fields.
# for this field we add an additional flag for delete and
# set the field to be non-strict
permissions_ext = EnumFlagField(
Group.Permissions,
strict=False,
choices=[
*utils.choices(Group.Permissions),
(1 << 3, "DELETE")
]
)
form = PermissionsExampleForm(
initial={
"permissions": Group.Permissions.READ | Group.Permissions.EXECUTE,
"permissions_ext": Group.Permissions.READ | Group.Permissions.WRITE | (1 << 3)
}
)
When we render this form using {{ form.as_p }} we get:
<form method="post">
<p>
<label for="id_permissions">Permissions:</label>
<select name="permissions" required="" id="id_permissions" multiple="">
<option value="1" selected="">READ</option>
<option value="2">WRITE</option>
<option value="4" selected="">EXECUTE</option>
</select>
</p>
<p>
<label for="id_permissions_ext">Permissions ext:</label>
<select name="permissions_ext" required="" id="id_permissions_ext" multiple="">
<option value="1" selected="">READ</option>
<option value="2" selected="">WRITE</option>
<option value="4">EXECUTE</option>
<!-- our non strict field allows bits outside of the enum to be set! -->
<option value="8" selected="">DELETE</option>
</select>
</p>
<button type="submit">Submit</button>
</form>
The default widgets used above derive from django.forms.SelectMultiple. We can also use
checkboxes instead by using django_enum.forms.FlagCheckbox and
django_enum.forms.NonStrictFlagCheckbox:
This example uses the
Permissionsenum from the flags howto.
from django.forms import Form
from django_enum.forms import EnumFlagField, FlagCheckbox, NonStrictFlagCheckbox
from django_enum import utils
class PermissionsExampleForm(Form):
permissions = EnumFlagField(Group.Permissions, widget=FlagCheckbox)
# form fields can be non-strict just like model fields.
# for this field we add an additional flag for delete and
# set the field to be non-strict
permissions_ext = EnumFlagField(
Group.Permissions,
strict=False,
choices=[
*utils.choices(Group.Permissions),
(1 << 3, "DELETE")
],
widget=NonStrictFlagCheckbox
)
form = PermissionsExampleForm(
initial={
"permissions": Group.Permissions.READ | Group.Permissions.EXECUTE,
"permissions_ext": Group.Permissions.READ | Group.Permissions.WRITE | (1 << 3)
}
)
When we render this form using {{ form.as_p }} we get:
<form method="post">
<p>
<label>Permissions:</label>
</p>
<ul id="id_permissions">
<li>
<label for="id_permissions_0">
<input type="checkbox" name="permissions" value="1" id="id_permissions_0" checked="">
READ
</label>
</li>
<li>
<label for="id_permissions_1">
<input type="checkbox" name="permissions" value="2" id="id_permissions_1">
WRITE
</label>
</li>
<li>
<label for="id_permissions_2">
<input type="checkbox" name="permissions" value="4" id="id_permissions_2" checked="">
EXECUTE
</label>
</li>
</ul>
<p></p>
<p>
<label>Permissions ext:</label>
</p>
<ul id="id_permissions_ext">
<li>
<label for="id_permissions_ext_0">
<input type="checkbox" name="permissions_ext" value="1" id="id_permissions_ext_0" checked="">
READ
</label>
</li>
<li>
<label for="id_permissions_ext_1">
<input type="checkbox" name="permissions_ext" value="2" id="id_permissions_ext_1" checked="">
WRITE
</label>
</li>
<li>
<label for="id_permissions_ext_2">
<input type="checkbox" name="permissions_ext" value="4" id="id_permissions_ext_2">
EXECUTE
</label>
</li>
<li>
<label for="id_permissions_ext_3">
<input type="checkbox" name="permissions_ext" value="8" id="id_permissions_ext_3" checked="">
DELETE
</label>
</li>
</ul>
<p></p>
<button type="submit">Submit</button>
</form>