codekingpro/portable-devtools
114k
1from .. import widgets2from .core import Field3from wtforms.utils import unset_value4 5__all__ = ("FormField",)6 7 8class FormField(Field):9 """10 Encapsulate a form as a field in another form.11 12 :param form_class:13 A subclass of Form that will be encapsulated.14 :param separator:15 A string which will be suffixed to this field's name to create the16 prefix to enclosed fields. The default is fine for most uses.17 """18 19 widget = widgets.TableWidget()20 21 def __init__(22 self, form_class, label=None, validators=None, separator="-", **kwargs23 ):24 super().__init__(label, validators, **kwargs)25 self.form_class = form_class26 self.separator = separator27 self._obj = None28 if self.filters:29 raise TypeError(30 "FormField cannot take filters, as the encapsulated"31 " data is not mutable."32 )33 if validators:34 raise TypeError(35 "FormField does not accept any validators. Instead,"36 " define them on the enclosed form."37 )38 39 def process(self, formdata, data=unset_value, extra_filters=None):40 if extra_filters:41 raise TypeError(42 "FormField cannot take filters, as the encapsulated"43 "data is not mutable."44 )45 46 if data is unset_value:47 try:48 data = self.default()49 except TypeError:50 data = self.default51 self._obj = data52 53 self.object_data = data54 55 prefix = self.name + self.separator56 if isinstance(data, dict):57 self.form = self.form_class(formdata=formdata, prefix=prefix, **data)58 else:59 self.form = self.form_class(formdata=formdata, obj=data, prefix=prefix)60 61 def validate(self, form, extra_validators=()):62 if extra_validators:63 raise TypeError(64 "FormField does not accept in-line validators, as it"65 " gets errors from the enclosed form."66 )67 return self.form.validate()68 69 def populate_obj(self, obj, name):70 candidate = getattr(obj, name, None)71 if candidate is None:72 if self._obj is None:73 raise TypeError(74 "populate_obj: cannot find a value to populate from"75 " the provided obj or input data/defaults"76 )77 candidate = self._obj78 79 self.form.populate_obj(candidate)80 setattr(obj, name, candidate)81 82 def __iter__(self):83 return iter(self.form)84 85 def __getitem__(self, name):86 return self.form[name]87 88 def __getattr__(self, name):89 return getattr(self.form, name)90 91 @property92 def data(self):93 return self.form.data94 95 @property96 def errors(self):97 return self.form.errors98 