form.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. import itertools
  2. try:
  3. from collections import OrderedDict
  4. except ImportError:
  5. from ordereddict import OrderedDict
  6. from wtforms.compat import with_metaclass, iteritems, itervalues
  7. from wtforms.meta import DefaultMeta
  8. __all__ = (
  9. 'BaseForm',
  10. 'Form',
  11. )
  12. class BaseForm(object):
  13. """
  14. Base Form Class. Provides core behaviour like field construction,
  15. validation, and data and error proxying.
  16. """
  17. def __init__(self, fields, prefix='', meta=DefaultMeta()):
  18. """
  19. :param fields:
  20. A dict or sequence of 2-tuples of partially-constructed fields.
  21. :param prefix:
  22. If provided, all fields will have their name prefixed with the
  23. value.
  24. :param meta:
  25. A meta instance which is used for configuration and customization
  26. of WTForms behaviors.
  27. """
  28. if prefix and prefix[-1] not in '-_;:/.':
  29. prefix += '-'
  30. self.meta = meta
  31. self._prefix = prefix
  32. self._errors = None
  33. self._fields = OrderedDict()
  34. if hasattr(fields, 'items'):
  35. fields = fields.items()
  36. translations = self._get_translations()
  37. extra_fields = []
  38. if meta.csrf:
  39. self._csrf = meta.build_csrf(self)
  40. extra_fields.extend(self._csrf.setup_form(self))
  41. for name, unbound_field in itertools.chain(fields, extra_fields):
  42. options = dict(name=name, prefix=prefix, translations=translations)
  43. field = meta.bind_field(self, unbound_field, options)
  44. self._fields[name] = field
  45. def __iter__(self):
  46. """Iterate form fields in creation order."""
  47. return iter(itervalues(self._fields))
  48. def __contains__(self, name):
  49. """ Returns `True` if the named field is a member of this form. """
  50. return (name in self._fields)
  51. def __getitem__(self, name):
  52. """ Dict-style access to this form's fields."""
  53. return self._fields[name]
  54. def __setitem__(self, name, value):
  55. """ Bind a field to this form. """
  56. self._fields[name] = value.bind(form=self, name=name, prefix=self._prefix)
  57. def __delitem__(self, name):
  58. """ Remove a field from this form. """
  59. del self._fields[name]
  60. def _get_translations(self):
  61. """
  62. .. deprecated:: 2.0
  63. `_get_translations` is being removed in WTForms 3.0, use
  64. `Meta.get_translations` instead.
  65. Override in subclasses to provide alternate translations factory.
  66. Must return an object that provides gettext() and ngettext() methods.
  67. """
  68. return self.meta.get_translations(self)
  69. def populate_obj(self, obj):
  70. """
  71. Populates the attributes of the passed `obj` with data from the form's
  72. fields.
  73. :note: This is a destructive operation; Any attribute with the same name
  74. as a field will be overridden. Use with caution.
  75. """
  76. for name, field in iteritems(self._fields):
  77. field.populate_obj(obj, name)
  78. def process(self, formdata=None, obj=None, data=None, **kwargs):
  79. """
  80. Take form, object data, and keyword arg input and have the fields
  81. process them.
  82. :param formdata:
  83. Used to pass data coming from the enduser, usually `request.POST` or
  84. equivalent.
  85. :param obj:
  86. If `formdata` is empty or not provided, this object is checked for
  87. attributes matching form field names, which will be used for field
  88. values.
  89. :param data:
  90. If provided, must be a dictionary of data. This is only used if
  91. `formdata` is empty or not provided and `obj` does not contain
  92. an attribute named the same as the field.
  93. :param `**kwargs`:
  94. If `formdata` is empty or not provided and `obj` does not contain
  95. an attribute named the same as a field, form will assign the value
  96. of a matching keyword argument to the field, if one exists.
  97. """
  98. formdata = self.meta.wrap_formdata(self, formdata)
  99. if data is not None:
  100. # XXX we want to eventually process 'data' as a new entity.
  101. # Temporarily, this can simply be merged with kwargs.
  102. kwargs = dict(data, **kwargs)
  103. for name, field, in iteritems(self._fields):
  104. if obj is not None and hasattr(obj, name):
  105. field.process(formdata, getattr(obj, name))
  106. elif name in kwargs:
  107. field.process(formdata, kwargs[name])
  108. else:
  109. field.process(formdata)
  110. def validate(self, extra_validators=None):
  111. """
  112. Validates the form by calling `validate` on each field.
  113. :param extra_validators:
  114. If provided, is a dict mapping field names to a sequence of
  115. callables which will be passed as extra validators to the field's
  116. `validate` method.
  117. Returns `True` if no errors occur.
  118. """
  119. self._errors = None
  120. success = True
  121. for name, field in iteritems(self._fields):
  122. if extra_validators is not None and name in extra_validators:
  123. extra = extra_validators[name]
  124. else:
  125. extra = tuple()
  126. if not field.validate(self, extra):
  127. success = False
  128. return success
  129. @property
  130. def data(self):
  131. return dict((name, f.data) for name, f in iteritems(self._fields))
  132. @property
  133. def errors(self):
  134. if self._errors is None:
  135. self._errors = dict((name, f.errors) for name, f in iteritems(self._fields) if f.errors)
  136. return self._errors
  137. class FormMeta(type):
  138. """
  139. The metaclass for `Form` and any subclasses of `Form`.
  140. `FormMeta`'s responsibility is to create the `_unbound_fields` list, which
  141. is a list of `UnboundField` instances sorted by their order of
  142. instantiation. The list is created at the first instantiation of the form.
  143. If any fields are added/removed from the form, the list is cleared to be
  144. re-generated on the next instantiation.
  145. Any properties which begin with an underscore or are not `UnboundField`
  146. instances are ignored by the metaclass.
  147. """
  148. def __init__(cls, name, bases, attrs):
  149. type.__init__(cls, name, bases, attrs)
  150. cls._unbound_fields = None
  151. cls._wtforms_meta = None
  152. def __call__(cls, *args, **kwargs):
  153. """
  154. Construct a new `Form` instance.
  155. Creates the `_unbound_fields` list and the internal `_wtforms_meta`
  156. subclass of the class Meta in order to allow a proper inheritance
  157. hierarchy.
  158. """
  159. if cls._unbound_fields is None:
  160. fields = []
  161. for name in dir(cls):
  162. if not name.startswith('_'):
  163. unbound_field = getattr(cls, name)
  164. if hasattr(unbound_field, '_formfield'):
  165. fields.append((name, unbound_field))
  166. # We keep the name as the second element of the sort
  167. # to ensure a stable sort.
  168. fields.sort(key=lambda x: (x[1].creation_counter, x[0]))
  169. cls._unbound_fields = fields
  170. # Create a subclass of the 'class Meta' using all the ancestors.
  171. if cls._wtforms_meta is None:
  172. bases = []
  173. for mro_class in cls.__mro__:
  174. if 'Meta' in mro_class.__dict__:
  175. bases.append(mro_class.Meta)
  176. cls._wtforms_meta = type('Meta', tuple(bases), {})
  177. return type.__call__(cls, *args, **kwargs)
  178. def __setattr__(cls, name, value):
  179. """
  180. Add an attribute to the class, clearing `_unbound_fields` if needed.
  181. """
  182. if name == 'Meta':
  183. cls._wtforms_meta = None
  184. elif not name.startswith('_') and hasattr(value, '_formfield'):
  185. cls._unbound_fields = None
  186. type.__setattr__(cls, name, value)
  187. def __delattr__(cls, name):
  188. """
  189. Remove an attribute from the class, clearing `_unbound_fields` if
  190. needed.
  191. """
  192. if not name.startswith('_'):
  193. cls._unbound_fields = None
  194. type.__delattr__(cls, name)
  195. class Form(with_metaclass(FormMeta, BaseForm)):
  196. """
  197. Declarative Form base class. Extends BaseForm's core behaviour allowing
  198. fields to be defined on Form subclasses as class attributes.
  199. In addition, form and instance input data are taken at construction time
  200. and passed to `process()`.
  201. """
  202. Meta = DefaultMeta
  203. def __init__(self, formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs):
  204. """
  205. :param formdata:
  206. Used to pass data coming from the enduser, usually `request.POST` or
  207. equivalent. formdata should be some sort of request-data wrapper which
  208. can get multiple parameters from the form input, and values are unicode
  209. strings, e.g. a Werkzeug/Django/WebOb MultiDict
  210. :param obj:
  211. If `formdata` is empty or not provided, this object is checked for
  212. attributes matching form field names, which will be used for field
  213. values.
  214. :param prefix:
  215. If provided, all fields will have their name prefixed with the
  216. value.
  217. :param data:
  218. Accept a dictionary of data. This is only used if `formdata` and
  219. `obj` are not present.
  220. :param meta:
  221. If provided, this is a dictionary of values to override attributes
  222. on this form's meta instance.
  223. :param `**kwargs`:
  224. If `formdata` is empty or not provided and `obj` does not contain
  225. an attribute named the same as a field, form will assign the value
  226. of a matching keyword argument to the field, if one exists.
  227. """
  228. meta_obj = self._wtforms_meta()
  229. if meta is not None and isinstance(meta, dict):
  230. meta_obj.update_values(meta)
  231. super(Form, self).__init__(self._unbound_fields, meta=meta_obj, prefix=prefix)
  232. for name, field in iteritems(self._fields):
  233. # Set all the fields to attributes so that they obscure the class
  234. # attributes with the same names.
  235. setattr(self, name, field)
  236. self.process(formdata, obj, data=data, **kwargs)
  237. def __setitem__(self, name, value):
  238. raise TypeError('Fields may not be added to Form instances, only classes.')
  239. def __delitem__(self, name):
  240. del self._fields[name]
  241. setattr(self, name, None)
  242. def __delattr__(self, name):
  243. if name in self._fields:
  244. self.__delitem__(name)
  245. else:
  246. # This is done for idempotency, if we have a name which is a field,
  247. # we want to mask it by setting the value to None.
  248. unbound_field = getattr(self.__class__, name, None)
  249. if unbound_field is not None and hasattr(unbound_field, '_formfield'):
  250. setattr(self, name, None)
  251. else:
  252. super(Form, self).__delattr__(name)
  253. def validate(self):
  254. """
  255. Validates the form by calling `validate` on each field, passing any
  256. extra `Form.validate_<fieldname>` validators to the field validator.
  257. """
  258. extra = {}
  259. for name in self._fields:
  260. inline = getattr(self.__class__, 'validate_%s' % name, None)
  261. if inline is not None:
  262. extra[name] = [inline]
  263. return super(Form, self).validate(extra)