Source code for facond.actions

"""
An Action may apply reversible modifications of a django Form.

It should always take a list of :py:cls:`~facond.conditions.Condition` as first
argument, and then whatever it's going to need to work.
"""
from collections import OrderedDict

from django import forms

from .js import JsDictMixin


[docs]class Action(JsDictMixin): """An action to take on a list of fields. The :py:meth:`~Action.execute()` will first execute :py:meth:`~facond.conditions.Condition.validate()` for every of its conditions against the :py:cls:`~facond.forms.Form` instance it is passed. """ js_attrs = ['field', 'conditions'] def __init__(self, conditions): """Instanciate with a list of condition to require.""" self.conditions = conditions
[docs] def execute(self, form): """Prevent the action from being applied if conditions don't pass.""" for condition in self.conditions: if not condition.validate(form): return self.apply(form) return self
[docs] def apply(self, form): """Actual application of the action on the form field.""" raise NotImplementedError()
[docs] def unapply(self, form): """Revert apply() action."""
[docs]class RemoveField(Action): """Remove fields from a form.""" def __init__(self, conditions, field): """Remove a field if conditions validate.""" super(RemoveField, self).__init__(conditions) self.field = field
[docs] def apply(self, form): """Remove the field and data from field.form.""" self.original_keys = list(form.fields.keys()) self.original_field = form.fields.pop(self.field) attr = self.original_field.widget.attrs.get('class', '') attr += ' facond-hide' self.original_field.widget.attrs['class'] = attr
[docs] def unapply(self, form): """Restore the field and data in field.form.""" original_field = getattr(self, 'original_field', None) if not original_field: return fields = OrderedDict() for key in self.original_keys: if key == self.field: fields[key] = original_field elif key in form.fields: fields[key] = form.fields[key] form.fields = fields
[docs]class RemoveChoices(Action): """Remove choices from a choice field.""" js_attrs = ['field', 'choices', 'conditions'] def __init__(self, conditions, field, choices): """List of choice values to remove if conditions pass.""" super(RemoveChoices, self).__init__(conditions) self.field = field self.choices = choices
[docs] def apply(self, form): """Raise a ValidationError if the field value is in self.values.""" values = form.data.get(self.field, None) if not isinstance(values, list): values = [values] for value in values: if value in self.choices: raise forms.ValidationError( form.fields[self.field].error_messages['invalid_choice'], code='invalid_choice', params={'value': value}, )