Source code for fleetingform.lib.form_generator
from django import forms
from fleetingform.models import FleetingFormControl
from fleetingform.widgets import (BootstrapDateTimePickerInput,
BootstrapDatePickerInput,
BootstrapTimePickerInput, )
[docs]def generate_fleeting_form_class_for(form_controls, query_params={}):
"""Generate a class for the given form and query parameters.
:param form_info: a dictionary that describes a Fleeting Form.
:type form_info: dict
:param query_params: URL query parameters.
:type query_params: django.http.QueryDict
Fleeting forms are all unique. To take advantage of Django's
form handling we need to generate a new class for each one.
This generator accepts a form described in a dictionary, using
the Fleeting Form shorthand.
.. code-block:: python
"template": {
# Actions are rendered as buttons at the bottom of the
# form. The name of the button clicked is stored in
# the ``action`` key of the result.
"actions": ["Submit", "Cancel"],
# Controls are the elements on the page the user interacts
# with. There can be up to 32 controls on a Fleeting Form.
# Controls will be rendered in the order they are listed.
"form_controls": [
# Controls have a name, type, optional help text, label, and
# initial value. Any field can be required for the form to
# be complete.
{
"name": "comments",
"type": "textarea",
"label": "User Comments",
"required": true,
"initial": "What did you think?"
},
{
"name": "toes",
"type": "integer",
"label": "How many toes?",
"required": true,
"initial": 10
},
{
"name": "Pies",
"type": "float",
"label": "How many pies are left?",
"required": true,
"initial": 3.25
},
# Fleeting forms automatically validate user input and render
# the correct form elements for you. Use the correct field
# type to get the most out of your form.
{
"name": "pet_name",
"type": "text",
"label": "Pet's Name",
"required": false,
"initial": "fido",
"help_text": "The short version."
"validations": [
{
"type": "max-length",
"params": {"max-length": 32},
"message": "Names must be 32 characters or fewer."
}
]
},
# Special field types are supported to provide extra
# validation for URLs and Emails.
{
"name": "website",
"type": "url",
"label": "Your Website",
"required": true,
"initial": "https://"
},
{
"name": "email",
"type": "email",
"label": "Your Email",
"required": true,
"help_text": "We will never send email without asking."
},
# For restricting user input, try the choices field. This
# will render a select and keep track of what the user
# chooses.
{
"name": "breed",
"type": "choice",
"label": "Breed",
"required": true,
"choices": [
["lab", "Labrador"],
["shepherd", "Shepherd"],
["collie", "Collier"],
["burmese", "Burmese Mountain Dog"]
]
},
# Dates and times use a special form widget so the user can
# select from a calendar or time picker.
{
"name": "incident_datetime",
"type": "datetime",
"label": "Incident Date and Time",
"required": true
},
{
"name": "moms_bday",
"type": "date",
"label": "Mom's Birthday",
"required": true
},
{
"name": "callback_time",
"type": "time",
"label": "Preferred Callback Time",
"required": false
},
# Boolean fields can be used to implement "I have read and..."
# forms, simply set them to required.
{
"name": "accept_terms",
"type": "boolean",
"label": "I have read and accept and terms.",
"required": true
},
]
}
For any field that does not have an initial value in the
Fleeting Form dictionary, if the field name is a key in
the GET query params then the query param value will
be used as the initial value.
Use this to customize a form default values, by adding a
username or other custom touch, to a form that is distributed
to many people.
"""
class GeneratedFleetingForm(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for control in form_controls:
name = control.name
self.fields[name] = self.get_field_for_control(control)
def get_field_for_control(self, control):
initial = control.initial or \
query_params.get(control.name, '')
kwargs = {
'label': control.label or control.name.title(),
'initial': initial,
'required': control.required,
'help_text': control.help_text,
'disabled': control.disabled,
# 'is_hidden': control.hidden
}
if control.type == FleetingFormControl.FIELD_TYPE_TEXTAREA:
kwargs['widget'] = forms.Textarea()
field = forms.CharField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_INTEGER:
field = forms.IntegerField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_FLOAT:
field = forms.FloatField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_DECIMAL:
kwargs['max_digits'] = control.params.get('max_digits', 21)
kwargs['decimal_places'] = control.params.get(
'decimal_places', 5)
field = forms.DecimalField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_BOOLEAN:
field = forms.BooleanField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_TIME:
kwargs['widget'] = BootstrapTimePickerInput()
kwargs['input_formats'] = ['%H:%M', '%I:%M%p', '%I:%M %p']
field = forms.TimeField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_DATE:
kwargs['widget'] = BootstrapDatePickerInput()
kwargs['input_formats'] = ['%d/%m/%Y', ]
field = forms.DateField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_DATETIME:
kwargs['widget'] = BootstrapDateTimePickerInput()
kwargs['input_formats'] = ['%d/%m/%Y %H:%M', ]
field = forms.DateTimeField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_URL:
field = forms.URLField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_EMAIL:
field = forms.EmailField(**kwargs)
elif control.type == FleetingFormControl.FIELD_TYPE_CHOICE:
kwargs['choices'] = control.choices.values_list(
'value', 'text')
field = forms.ChoiceField(**kwargs)
else:
field = forms.CharField(**kwargs)
if control.hidden:
field.widget = forms.HiddenInput()
return field
return GeneratedFleetingForm