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