form.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. from flask import current_app
  2. from flask import request
  3. from flask import session
  4. from markupsafe import Markup
  5. from werkzeug.datastructures import CombinedMultiDict
  6. from werkzeug.datastructures import ImmutableMultiDict
  7. from werkzeug.utils import cached_property
  8. from wtforms import Form
  9. from wtforms.meta import DefaultMeta
  10. from wtforms.widgets import HiddenInput
  11. from .csrf import _FlaskFormCSRF
  12. try:
  13. from .i18n import translations
  14. except ImportError:
  15. translations = None # babel not installed
  16. SUBMIT_METHODS = {"POST", "PUT", "PATCH", "DELETE"}
  17. _Auto = object()
  18. class FlaskForm(Form):
  19. """Flask-specific subclass of WTForms :class:`~wtforms.form.Form`.
  20. If ``formdata`` is not specified, this will use :attr:`flask.request.form`
  21. and :attr:`flask.request.files`. Explicitly pass ``formdata=None`` to
  22. prevent this.
  23. """
  24. class Meta(DefaultMeta):
  25. csrf_class = _FlaskFormCSRF
  26. csrf_context = session # not used, provided for custom csrf_class
  27. @cached_property
  28. def csrf(self):
  29. return current_app.config.get("WTF_CSRF_ENABLED", True)
  30. @cached_property
  31. def csrf_secret(self):
  32. return current_app.config.get("WTF_CSRF_SECRET_KEY", current_app.secret_key)
  33. @cached_property
  34. def csrf_field_name(self):
  35. return current_app.config.get("WTF_CSRF_FIELD_NAME", "csrf_token")
  36. @cached_property
  37. def csrf_time_limit(self):
  38. return current_app.config.get("WTF_CSRF_TIME_LIMIT", 3600)
  39. def wrap_formdata(self, form, formdata):
  40. if formdata is _Auto:
  41. if _is_submitted():
  42. if request.files:
  43. return CombinedMultiDict((request.files, request.form))
  44. elif request.form:
  45. return request.form
  46. elif request.is_json:
  47. return ImmutableMultiDict(request.get_json())
  48. return None
  49. return formdata
  50. def get_translations(self, form):
  51. if not current_app.config.get("WTF_I18N_ENABLED", True):
  52. return super().get_translations(form)
  53. return translations
  54. def __init__(self, formdata=_Auto, **kwargs):
  55. super().__init__(formdata=formdata, **kwargs)
  56. def is_submitted(self):
  57. """Consider the form submitted if there is an active request and
  58. the method is ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
  59. """
  60. return _is_submitted()
  61. def validate_on_submit(self, extra_validators=None):
  62. """Call :meth:`validate` only if the form is submitted.
  63. This is a shortcut for ``form.is_submitted() and form.validate()``.
  64. """
  65. return self.is_submitted() and self.validate(extra_validators=extra_validators)
  66. def hidden_tag(self, *fields):
  67. """Render the form's hidden fields in one call.
  68. A field is considered hidden if it uses the
  69. :class:`~wtforms.widgets.HiddenInput` widget.
  70. If ``fields`` are given, only render the given fields that
  71. are hidden. If a string is passed, render the field with that
  72. name if it exists.
  73. .. versionchanged:: 0.13
  74. No longer wraps inputs in hidden div.
  75. This is valid HTML 5.
  76. .. versionchanged:: 0.13
  77. Skip passed fields that aren't hidden.
  78. Skip passed names that don't exist.
  79. """
  80. def hidden_fields(fields):
  81. for f in fields:
  82. if isinstance(f, str):
  83. f = getattr(self, f, None)
  84. if f is None or not isinstance(f.widget, HiddenInput):
  85. continue
  86. yield f
  87. return Markup("\n".join(str(f) for f in hidden_fields(fields or self)))
  88. def _is_submitted():
  89. """Consider the form submitted if there is an active request and
  90. the method is ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
  91. """
  92. return bool(request) and request.method in SUBMIT_METHODS