def __init__(self, form, context, *args, **kwargs): """ Dynamically add each of the form fields for the given form model instance and its related field model instances. """ self.form = form self.form_fields = form.fields.visible() initial = kwargs.pop("initial", {}) # If a FormEntry instance is given to edit, populate initial # with its field values. field_entries = {} if kwargs.get("instance"): for field_entry in kwargs["instance"].fields.all(): field_entries[field_entry.field_id] = field_entry.value super(FormForForm, self).__init__(*args, **kwargs) # Create the form fields. for field in self.form_fields: field_key = "field_%s" % field.id field_class = fields.CLASSES[field.field_type] field_widget = fields.WIDGETS.get(field.field_type) field_args = { "label": field.label, "required": field.required, "help_text": field.help_text } arg_names = field_class.__init__.__code__.co_varnames if "max_length" in arg_names: field_args["max_length"] = settings.FORMS_FIELD_MAX_LENGTH if "choices" in arg_names: choices = list(field.get_choices()) if (field.field_type == fields.SELECT and field.default not in [c[0] for c in choices]): choices.insert(0, ("", field.placeholder_text)) field_args["choices"] = choices if field_widget is not None: field_args["widget"] = field_widget # # Initial value for field, in order of preference: # # - If a form model instance is given (eg we're editing a # form response), then use the instance's value for the # field. # - If the developer has provided an explicit "initial" # dict, use it. # - The default value for the field instance as given in # the admin. # initial_val = None try: initial_val = field_entries[field.id] except KeyError: try: initial_val = initial[field_key] except KeyError: initial_val = str(Template(field.default).render(context)) if initial_val: if field.is_a(*fields.MULTIPLE): initial_val = split_choices(initial_val) elif field.field_type == fields.CHECKBOX: initial_val = initial_val != "False" self.initial[field_key] = initial_val self.fields[field_key] = field_class(**field_args) if field.field_type == fields.DOB: _now = datetime.now() years = list(range(_now.year, _now.year - 120, -1)) self.fields[field_key].widget.years = years # Add identifying type attr to the field for styling. setattr(self.fields[field_key], "type", field_class.__name__.lower()) if (field.required and settings.FORMS_USE_HTML5 and field.field_type != fields.CHECKBOX_MULTIPLE): self.fields[field_key].widget.attrs["required"] = "" if field.placeholder_text and not field.default: text = field.placeholder_text self.fields[field_key].widget.attrs["placeholder"] = text
# The filter function for each filter type FILTER_FUNCS = { FILTER_CHOICE_CONTAINS: lambda val, field: val.lower() in field.lower(), FILTER_CHOICE_DOESNT_CONTAIN: lambda val, field: val.lower() not in field.lower(), FILTER_CHOICE_EQUALS: lambda val, field: val.lower() == field.lower(), FILTER_CHOICE_DOESNT_EQUAL: lambda val, field: val.lower() != field.lower(), FILTER_CHOICE_BETWEEN: lambda val_from, val_to, field: ((not val_from or val_from <= field) and (not val_to or val_to >= field)), FILTER_CHOICE_CONTAINS_ANY: lambda val, field: set(val) & set(split_choices(field)), FILTER_CHOICE_CONTAINS_ALL: lambda val, field: set(val) == set(split_choices(field)), FILTER_CHOICE_DOESNT_CONTAIN_ANY: lambda val, field: not set(val) & set(split_choices(field)), FILTER_CHOICE_DOESNT_CONTAIN_ALL: lambda val, field: set(val) != set(split_choices(field)), } # Export form fields for each filter type grouping text_filter_field = forms.ChoiceField(label=" ", required=False, choices=TEXT_FILTER_CHOICES) choice_filter_field = forms.ChoiceField(label=" ", required=False, choices=CHOICE_FILTER_CHOICES)
FILTER_FUNCS = { FILTER_CHOICE_CONTAINS: lambda val, field: val.lower() in field.lower(), FILTER_CHOICE_DOESNT_CONTAIN: lambda val, field: val.lower() not in field.lower(), FILTER_CHOICE_EQUALS: lambda val, field: val.lower() == field.lower(), FILTER_CHOICE_DOESNT_EQUAL: lambda val, field: val.lower() != field.lower(), FILTER_CHOICE_BETWEEN: lambda val_from, val_to, field: ( (not val_from or val_from <= field) and (not val_to or val_to >= field) ), FILTER_CHOICE_CONTAINS_ANY: lambda val, field: set(val) & set(split_choices(field)), FILTER_CHOICE_CONTAINS_ALL: lambda val, field: set(val) == set(split_choices(field)), FILTER_CHOICE_DOESNT_CONTAIN_ANY: lambda val, field: not set(val) & set(split_choices(field)), FILTER_CHOICE_DOESNT_CONTAIN_ALL: lambda val, field: set(val) != set(split_choices(field)), } # Export form fields for each filter type grouping text_filter_field = forms.ChoiceField(label=" ", required=False, choices=TEXT_FILTER_CHOICES) choice_filter_field = forms.ChoiceField(label=" ", required=False, choices=CHOICE_FILTER_CHOICES) multiple_filter_field = forms.ChoiceField(label=" ", required=False, choices=MULTIPLE_FILTER_CHOICES)
def __init__(self, form, context, *args, **kwargs): """ Dynamically add each of the form fields for the given form model instance and its related field model instances. """ self.form = form self.form_fields = form.fields.visible() initial = kwargs.pop("initial", {}) # If a FormEntry instance is given to edit, populate initial # with its field values. field_entries = {} if kwargs.get("instance"): for field_entry in kwargs["instance"].fields.all(): field_entries[field_entry.field_id] = field_entry.value super(FormForForm, self).__init__(*args, **kwargs) # Create the form fields. for field in self.form_fields: field_key = "field_%s" % field.id field_class = fields.CLASSES[field.field_type] field_widget = fields.WIDGETS.get(field.field_type) field_args = {"label": field.label, "required": field.required, "help_text": field.help_text} if field.required and not field.help_text: field_args["help_text"] = _("required") arg_names = field_class.__init__.__code__.co_varnames if "max_length" in arg_names: field_args["max_length"] = settings.FORMS_FIELD_MAX_LENGTH if "choices" in arg_names: field_args["choices"] = field.get_choices() if field_widget is not None: field_args["widget"] = field_widget # # Initial value for field, in order of preference: # # - If a form model instance is given (eg we're editing a # form response), then use the instance's value for the # field. # - If the developer has provided an explicit "initial" # dict, use it. # - The default value for the field instance as given in # the admin. # initial_val = None try: initial_val = field_entries[field.id] except KeyError: try: initial_val = initial[field_key] except KeyError: initial_val = Template(field.default).render(context) if initial_val: if field.is_a(*fields.MULTIPLE): initial_val = split_choices(initial_val) elif field.field_type == fields.CHECKBOX: initial_val = initial_val != "False" self.initial[field_key] = initial_val self.fields[field_key] = field_class(**field_args) if field.field_type == fields.DOB: _now = datetime.now() years = list(range(_now.year, _now.year - 120, -1)) self.fields[field_key].widget.years = years # Add identifying type attr to the field for styling. setattr(self.fields[field_key], "type", field_class.__name__.lower()) if (field.required and settings.FORMS_USE_HTML5 and field.field_type != fields.CHECKBOX_MULTIPLE): self.fields[field_key].widget.attrs["required"] = "" if field.placeholder_text and not field.default: text = field.placeholder_text self.fields[field_key].widget.attrs["placeholder"] = text
(FILTER_CHOICE_DOESNT_CONTAIN_ALL, _("Doesn't contain all")), ) # Dates DATE_FILTER_CHOICES = (("", _("Nothing")), (FILTER_CHOICE_BETWEEN, _("Is between"))) # The filter function for each filter type FILTER_FUNCS = { FILTER_CHOICE_CONTAINS: lambda val, field: val.lower() in field.lower(), FILTER_CHOICE_DOESNT_CONTAIN: lambda val, field: val.lower() not in field.lower(), FILTER_CHOICE_EQUALS: lambda val, field: val.lower() == field.lower(), FILTER_CHOICE_DOESNT_EQUAL: lambda val, field: val.lower() != field.lower(), FILTER_CHOICE_BETWEEN: lambda val_from, val_to, field: ( (not val_from or val_from <= field) and (not val_to or val_to >= field) ), FILTER_CHOICE_CONTAINS_ANY: lambda val, field: set(val) & set(split_choices(field)), FILTER_CHOICE_CONTAINS_ALL: lambda val, field: set(val) == set(split_choices(field)), FILTER_CHOICE_DOESNT_CONTAIN_ANY: lambda val, field: not set(val) & set(split_choices(field)), FILTER_CHOICE_DOESNT_CONTAIN_ALL: lambda val, field: set(val) != set(split_choices(field)), } # Export form fields for each filter type grouping text_filter_field = forms.ChoiceField(label=" ", required=False, choices=TEXT_FILTER_CHOICES) choice_filter_field = forms.ChoiceField(label=" ", required=False, choices=CHOICE_FILTER_CHOICES) multiple_filter_field = forms.ChoiceField(label=" ", required=False, choices=MULTIPLE_FILTER_CHOICES) date_filter_field = forms.ChoiceField(label=" ", required=False, choices=DATE_FILTER_CHOICES) class FormForForm(forms.ModelForm): """ Form with a set of fields dynamically assigned, directly based on the