.\" Man page generated from reStructuredText. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "FLASK-WTF" "1" "Apr 08, 2024" "1.2.x" "Flask-WTF" .SH NAME flask-wtf \- Flask-WTF 1.2.1 [image: Flask-WTF] [image] .sp Simple integration of \fI\%Flask\fP and \fI\%WTForms\fP, including CSRF, file upload, and reCAPTCHA. .SH FEATURES .INDENT 0.0 .IP \(bu 2 Integration with WTForms. .IP \(bu 2 Secure Form with CSRF token. .IP \(bu 2 Global CSRF protection. .IP \(bu 2 reCAPTCHA support. .IP \(bu 2 File upload that works with Flask\-Uploads. .IP \(bu 2 Internationalization using Flask\-Babel. .UNINDENT .SH USER'S GUIDE .sp This part of the documentation, which is mostly prose, begins with some background information about Flask\-WTF, then focuses on step\-by\-step instructions for getting the most out of Flask\-WTF. .SS Installation .sp The \fI\%Python Packaging Guide\fP contains general information about how to manage your project and dependencies. .SS Released version .sp Install or upgrade using pip. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C pip install \-U Flask\-WTF .ft P .fi .UNINDENT .UNINDENT .SS Development .sp The latest code is available from \fI\%GitHub\fP\&. Clone the repository then install using pip. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C git clone https://github.com/wtforms/flask\-wtf pip install \-e ./flask\-wtf .ft P .fi .UNINDENT .UNINDENT .sp Or install the latest build from an \fI\%archive\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C pip install \-U https://github.com/wtforms/flask\-wtf/archive/main.tar.gz .ft P .fi .UNINDENT .UNINDENT .SS Quickstart .sp Eager to get started? This page gives a good introduction to Flask\-WTF. It assumes you already have Flask\-WTF installed. If you do not, head over to the \fI\%Installation\fP section. .SS Creating Forms .sp Flask\-WTF provides your Flask application integration with WTForms. For example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C from flask_wtf import FlaskForm from wtforms import StringField from wtforms.validators import DataRequired class MyForm(FlaskForm): name = StringField(\(aqname\(aq, validators=[DataRequired()]) .ft P .fi .UNINDENT .UNINDENT .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 From version 0.9.0, Flask\-WTF will not import anything from wtforms, you need to import fields from wtforms. .UNINDENT .UNINDENT .sp In addition, a CSRF token hidden field is created automatically. You can render this in your template: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C
{{ form.csrf_token }} {{ form.name.label }} {{ form.name(size=20) }}
.ft P .fi .UNINDENT .UNINDENT .sp If your form has multiple hidden fields, you can render them in one block using \fBhidden_tag()\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C
{{ form.hidden_tag() }} {{ form.name.label }} {{ form.name(size=20) }}
.ft P .fi .UNINDENT .UNINDENT .SS Validating Forms .sp Validating the request in your view handlers: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C @app.route(\(aq/submit\(aq, methods=[\(aqGET\(aq, \(aqPOST\(aq]) def submit(): form = MyForm() if form.validate_on_submit(): return redirect(\(aq/success\(aq) return render_template(\(aqsubmit.html\(aq, form=form) .ft P .fi .UNINDENT .UNINDENT .sp Note that you don\(aqt have to pass \fBrequest.form\fP to Flask\-WTF; it will load automatically. And the convenient \fBvalidate_on_submit\fP will check if it is a POST request and if it is valid. .sp If your forms include validation, you\(aqll need to add to your template to display any error messages. Using the \fBform.name\fP field from the example above, that would look like this: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C {% if form.name.errors %} {% endif %} .ft P .fi .UNINDENT .UNINDENT .sp Heading over to \fI\%Creating Forms\fP to learn more skills. .SS Creating Forms .SS Secure Form .sp Without any configuration, the \fBFlaskForm\fP will be a session secure form with csrf protection. We encourage you not to change this. .sp But if you want to disable the csrf protection, you can pass: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C form = FlaskForm(meta={\(aqcsrf\(aq: False}) .ft P .fi .UNINDENT .UNINDENT .sp You can disable it globally—though you really shouldn\(aqt—with the configuration: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C WTF_CSRF_ENABLED = False .ft P .fi .UNINDENT .UNINDENT .sp In order to generate the csrf token, you must have a secret key, this is usually the same as your Flask app secret key. If you want to use another secret key, config it: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C WTF_CSRF_SECRET_KEY = \(aqa random string\(aq .ft P .fi .UNINDENT .UNINDENT .SS File Uploads .sp The \fBFileField\fP provided by Flask\-WTF differs from the WTForms\-provided field. It will check that the file is a non\-empty instance of \fBFileStorage\fP, otherwise \fBdata\fP will be \fBNone\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileRequired from werkzeug.utils import secure_filename class PhotoForm(FlaskForm): photo = FileField(validators=[FileRequired()]) @app.route(\(aq/upload\(aq, methods=[\(aqGET\(aq, \(aqPOST\(aq]) def upload(): form = PhotoForm() if form.validate_on_submit(): f = form.photo.data filename = secure_filename(f.filename) f.save(os.path.join( app.instance_path, \(aqphotos\(aq, filename )) return redirect(url_for(\(aqindex\(aq)) return render_template(\(aqupload.html\(aq, form=form) .ft P .fi .UNINDENT .UNINDENT .sp Similarly, you can use the \fBMultipleFileField\fP provided by Flask\-WTF to handle multiple files. It will check that the files is a list of non\-empty instance of \fBFileStorage\fP, otherwise \fBdata\fP will be \fBNone\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C from flask_wtf import FlaskForm from flask_wtf.file import MultipleFileField, FileRequired from werkzeug.utils import secure_filename class PhotoForm(FlaskForm): photos = MultipleFileField(validators=[FileRequired()]) @app.route(\(aq/upload\(aq, methods=[\(aqGET\(aq, \(aqPOST\(aq]) def upload(): form = PhotoForm() if form.validate_on_submit(): for f in form.photo.data: # form.photo.data return a list of FileStorage object filename = secure_filename(f.filename) f.save(os.path.join( app.instance_path, \(aqphotos\(aq, filename )) return redirect(url_for(\(aqindex\(aq)) return render_template(\(aqupload.html\(aq, form=form) .ft P .fi .UNINDENT .UNINDENT .sp Remember to set the \fBenctype\fP of the HTML form to \fBmultipart/form\-data\fP, otherwise \fBrequest.files\fP will be empty. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C
...
.ft P .fi .UNINDENT .UNINDENT .sp Flask\-WTF handles passing form data to the form for you. If you pass in the data explicitly, remember that \fBrequest.form\fP must be combined with \fBrequest.files\fP for the form to see the file data. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C form = PhotoForm() # is equivalent to: from flask import request from werkzeug.datastructures import CombinedMultiDict form = PhotoForm(CombinedMultiDict((request.files, request.form))) .ft P .fi .UNINDENT .UNINDENT .SS Validation .sp Flask\-WTF supports validating file uploads with \fBFileRequired\fP, \fBFileAllowed\fP, and \fBFileSize\fP\&. They can be used with both Flask\-WTF\(aqs and WTForms\(aqs \fBFileField\fP and \fBMultipleFileField\fP classes. .sp \fBFileAllowed\fP works well with Flask\-Uploads. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C from flask_uploads import UploadSet, IMAGES from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileAllowed, FileRequired images = UploadSet(\(aqimages\(aq, IMAGES) class UploadForm(FlaskForm): upload = FileField(\(aqimage\(aq, validators=[ FileRequired(), FileAllowed(images, \(aqImages only!\(aq) ]) .ft P .fi .UNINDENT .UNINDENT .sp It can be used without Flask\-Uploads by passing the extensions directly. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C class UploadForm(FlaskForm): upload = FileField(\(aqimage\(aq, validators=[ FileRequired(), FileAllowed([\(aqjpg\(aq, \(aqpng\(aq], \(aqImages only!\(aq) ]) .ft P .fi .UNINDENT .UNINDENT .SS Recaptcha .sp Flask\-WTF also provides Recaptcha support through a \fBRecaptchaField\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C from flask_wtf import FlaskForm, RecaptchaField from wtforms import TextField class SignupForm(FlaskForm): username = TextField(\(aqUsername\(aq) recaptcha = RecaptchaField() .ft P .fi .UNINDENT .UNINDENT .sp This comes with a number of configuration variables, some of which you have to configure. .TS center; |l|l|. _ T{ RECAPTCHA_PUBLIC_KEY T} T{ \fBrequired\fP A public key. T} _ T{ RECAPTCHA_PRIVATE_KEY T} T{ \fBrequired\fP A private key. T} _ T{ RECAPTCHA_API_SERVER T} T{ \fBoptional\fP Specify your Recaptcha API server. T} _ T{ RECAPTCHA_PARAMETERS T} T{ \fBoptional\fP A dict of JavaScript (api.js) parameters. T} _ T{ RECAPTCHA_DATA_ATTRS T} T{ \fBoptional\fP A dict of data attributes options. \fI\%https://developers.google.com/recaptcha/docs/display#javascript_resource_apijs_parameters\fP T} _ .TE .sp Example of RECAPTCHA_PARAMETERS, and RECAPTCHA_DATA_ATTRS: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C RECAPTCHA_PARAMETERS = {\(aqhl\(aq: \(aqzh\(aq, \(aqrender\(aq: \(aqexplicit\(aq} RECAPTCHA_DATA_ATTRS = {\(aqtheme\(aq: \(aqdark\(aq} .ft P .fi .UNINDENT .UNINDENT .sp For your convenience, when testing your application, if \fBapp.testing\fP is \fBTrue\fP, the recaptcha field will always be valid. .sp And it can be easily setup in the templates: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C
{{ form.username }} {{ form.recaptcha }}
.ft P .fi .UNINDENT .UNINDENT .sp We have an example for you: \fI\%recaptcha@github\fP\&. .SS CSRF Protection .sp Any view using \fBFlaskForm\fP to process the request is already getting CSRF protection. If you have views that don\(aqt use \fBFlaskForm\fP or make AJAX requests, use the provided CSRF extension to protect those requests as well. .SS Setup .sp To enable CSRF protection globally for a Flask app, register the \fBCSRFProtect\fP extension. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C from flask_wtf.csrf import CSRFProtect csrf = CSRFProtect(app) .ft P .fi .UNINDENT .UNINDENT .sp Like other Flask extensions, you can apply it lazily: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C csrf = CSRFProtect() def create_app(): app = Flask(__name__) csrf.init_app(app) .ft P .fi .UNINDENT .UNINDENT .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 CSRF protection requires a secret key to securely sign the token. By default this will use the Flask app\(aqs \fBSECRET_KEY\fP\&. If you\(aqd like to use a separate token you can set \fBWTF_CSRF_SECRET_KEY\fP\&. .UNINDENT .UNINDENT .SS HTML Forms .sp When using a \fBFlaskForm\fP, render the form\(aqs CSRF field like normal. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C
{{ form.csrf_token }}
.ft P .fi .UNINDENT .UNINDENT .sp If the template doesn\(aqt use a \fBFlaskForm\fP, render a hidden input with the token in the form. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C
.ft P .fi .UNINDENT .UNINDENT .SS JavaScript Requests .sp When sending an AJAX request, add the \fBX\-CSRFToken\fP header to it. For example, in jQuery you can configure all requests to send the token. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C .ft P .fi .UNINDENT .UNINDENT .sp In Axios you can set the header for all requests with \fBaxios.defaults.headers.common\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C .ft P .fi .UNINDENT .UNINDENT .SS Customize the error response .sp When CSRF validation fails, it will raise a \fBCSRFError\fP\&. By default this returns a response with the failure reason and a 400 code. You can customize the error response using Flask\(aqs \fI\%errorhandler()\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C from flask_wtf.csrf import CSRFError @app.errorhandler(CSRFError) def handle_csrf_error(e): return render_template(\(aqcsrf_error.html\(aq, reason=e.description), 400 .ft P .fi .UNINDENT .UNINDENT .SS Exclude views from protection .sp We strongly suggest that you protect all your views with CSRF. But if needed, you can exclude some views using a decorator. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C @app.route(\(aq/foo\(aq, methods=(\(aqGET\(aq, \(aqPOST\(aq)) @csrf.exempt def my_handler(): # ... return \(aqok\(aq .ft P .fi .UNINDENT .UNINDENT .sp You can exclude all the views of a blueprint. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C csrf.exempt(account_blueprint) .ft P .fi .UNINDENT .UNINDENT .sp You can disable CSRF protection in all views by default, by setting \fBWTF_CSRF_CHECK_DEFAULT\fP to \fBFalse\fP, and selectively call \fBprotect()\fP only when you need. This also enables you to do some pre\-processing on the requests before checking for the CSRF token. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C @app.before_request def check_csrf(): if not is_oauth(request): csrf.protect() .ft P .fi .UNINDENT .UNINDENT .SS Configuration .TS center; |l|l|. _ T{ \fBWTF_CSRF_ENABLED\fP T} T{ Set to \fBFalse\fP to disable all CSRF protection. Default is \fBTrue\fP\&. T} _ T{ \fBWTF_CSRF_CHECK_DEFAULT\fP T} T{ When using the CSRF protection extension, this controls whether every view is protected by default. Default is \fBTrue\fP\&. T} _ T{ \fBWTF_CSRF_SECRET_KEY\fP T} T{ Random data for generating secure tokens. If this is not set then \fBSECRET_KEY\fP is used. T} _ T{ \fBWTF_CSRF_METHODS\fP T} T{ HTTP methods to protect from CSRF. Default is \fB{\(aqPOST\(aq, \(aqPUT\(aq, \(aqPATCH\(aq, \(aqDELETE\(aq}\fP\&. T} _ T{ \fBWTF_CSRF_FIELD_NAME\fP T} T{ Name of the form field and session key that holds the CSRF token. Default is \fBcsrf_token\fP\&. T} _ T{ \fBWTF_CSRF_HEADERS\fP T} T{ HTTP headers to search for CSRF token when it is not provided in the form. Default is \fB[\(aqX\-CSRFToken\(aq, \(aqX\-CSRF\-Token\(aq]\fP\&. T} _ T{ \fBWTF_CSRF_TIME_LIMIT\fP T} T{ Max age in seconds for CSRF tokens. Default is \fB3600\fP\&. If set to \fBNone\fP, the CSRF token is valid for the life of the session. T} _ T{ \fBWTF_CSRF_SSL_STRICT\fP T} T{ Whether to enforce the same origin policy by checking that the referrer matches the host. Only applies to HTTPS requests. Default is \fBTrue\fP\&. T} _ T{ \fBWTF_I18N_ENABLED\fP T} T{ Set to \fBFalse\fP to disable Flask\-Babel I18N support. Also set to \fBFalse\fP if you want to use WTForms\(aqs built\-in messages directly, see more info \fI\%here\fP\&. Default is \fBTrue\fP\&. T} _ .TE .SS Recaptcha .TS center; |l|l|. _ T{ \fBRECAPTCHA_PUBLIC_KEY\fP T} T{ \fBrequired\fP A public key. T} _ T{ \fBRECAPTCHA_PRIVATE_KEY\fP T} T{ \fBrequired\fP A private key. \fI\%https://www.google.com/recaptcha/admin\fP T} _ T{ \fBRECAPTCHA_PARAMETERS\fP T} T{ \fBoptional\fP A dict of configuration options. T} _ T{ \fBRECAPTCHA_HTML\fP T} T{ \fBoptional\fP Override default HTML template for Recaptcha. T} _ T{ \fBRECAPTCHA_DATA_ATTRS\fP T} T{ \fBoptional\fP A dict of \fBdata\-\fP attrs to use for Recaptcha div T} _ T{ \fBRECAPTCHA_SCRIPT\fP T} T{ \fBoptional\fP Override the default captcha script URI in case an alternative service to reCAPtCHA, e.g. hCaptcha is used. Default is \fB\(aqhttps://www.google.com/recaptcha/api.js\(aq\fP T} _ T{ \fBRECAPTCHA_DIV_CLASS\fP T} T{ \fBoptional\fP Override the default class of the captcha div in case an alternative captcha service is used. Default is \fB\(aqg\-recaptcha\(aq\fP T} _ T{ \fBRECAPTCHA_VERIFY_SERVER\fP T} T{ \fBoptional\fP Override the default verification server in case an alternative service is used. Default is \fB\(aqhttps://www.google.com/recaptcha/api/siteverify\(aq\fP T} _ .TE .SS Logging .sp CSRF errors are logged at the \fBINFO\fP level to the \fBflask_wtf.csrf\fP logger. You still need to configure logging in your application in order to see these messages. .SH API DOCUMENTATION .sp If you are looking for information on a specific function, class or method, this part of the documentation is for you. .SS Developer Interface .SS Forms and Fields .SS CSRF Protection .SH ADDITIONAL NOTES .sp Legal information and changelog are here. .SS BSD\-3\-Clause License .sp Copyright 2010 WTForms .sp Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: .INDENT 0.0 .IP 1. 3 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. .IP 2. 3 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. .IP 3. 3 Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. .UNINDENT .sp THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \(dqAS IS\(dq AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SS Changes .SS Version 1.2.1 .sp Released 2023\-10\-02 .INDENT 0.0 .IP \(bu 2 Fix a bug introduced with \fI\%#556\fP where file validators were editing the file fields content. \fI\%#578\fP .UNINDENT .SS Version 1.2.0 .sp Released 2023\-10\-01 .INDENT 0.0 .IP \(bu 2 Add field \fBMultipleFileField\fP\&. \fBFileRequired\fP, \fBFileAllowed\fP, \fBFileSize\fP now can be used to validate multiple files \fI\%#556\fP \fI\%#338\fP .UNINDENT .SS Version 1.1.2 .sp Released 2023\-09\-29 .INDENT 0.0 .IP \(bu 2 Fixed Flask 2.3 deprecations of \fBwerkzeug.urls.url_encode\fP and \fBflask.Markup\fP \fI\%#565\fP \fI\%#561\fP .IP \(bu 2 Stop support for python 3.7 \fI\%#574\fP .IP \(bu 2 Use \fIpyproject.toml\fP instead of \fIsetup.cfg\fP \fI\%#576\fP .IP \(bu 2 Fixed nested blueprint CSRF exemption \fI\%#572\fP .UNINDENT .SS Version 1.1.1 .sp Released 2023\-01\-17 .INDENT 0.0 .IP \(bu 2 Fixed \fIvalidate\fP \fIextra_validators\fP parameter. \fI\%#548\fP .UNINDENT .SS Version 1.1.0 .sp Released 2023\-01\-15 .INDENT 0.0 .IP \(bu 2 Drop support for Python 3.6. .IP \(bu 2 \fBvalidate_on_submit\fP takes a \fBextra_validators\fP parameters \fI\%#479\fP .IP \(bu 2 Stop supporting Flask\-Babelex \fI\%#540\fP .IP \(bu 2 Support for python 3.11 \fI\%#542\fP .IP \(bu 2 Remove unused call to \fIJSONEncoder\fP \fI\%#536\fP .UNINDENT .SS Version 1.0.1 .sp Released 2022\-03\-31 .INDENT 0.0 .IP \(bu 2 Update compatibility with the latest Werkzeug release. \fI\%#511\fP .UNINDENT .SS Version 1.0.0 .sp Released 2021\-11\-07 .INDENT 0.0 .IP \(bu 2 Deprecated items removal \fI\%#484\fP .IP \(bu 2 Support for alternatives captcha services \fI\%#425\fP \fI\%#342\fP \fI\%#387\fP \fI\%#384\fP .UNINDENT .SS Version 0.15.1 .sp Released 2021\-05\-25 .INDENT 0.0 .IP \(bu 2 Add \fBpython_requires\fP metadata to avoid installing on unsupported Python versions. \fI\%#442\fP .UNINDENT .SS Version 0.15.0 .sp Released 2021\-05\-24 .INDENT 0.0 .IP \(bu 2 Drop support for Python < 3.6. \fI\%#416\fP .IP \(bu 2 \fBFileSize\fP validator. \fI\%#307\fP\fI\%#365\fP .IP \(bu 2 Extra requirement \fBemail\fP installs the \fBemail_validator\fP package. \fI\%#423\fP .IP \(bu 2 Fixed Flask 2.0 warnings. \fI\%#434\fP .IP \(bu 2 Various documentation fixes. \fI\%#315\fP\fI\%#321\fP\fI\%#335\fP\fI\%#344\fP\fI\%#386\fP\fI\%#400\fP, \fI\%#404\fP\fI\%#420\fP\fI\%#437\fP .IP \(bu 2 Various CI fixes. \fI\%#405\fP\fI\%#438\fP .UNINDENT .SS Version 0.14.3 .sp Released 2020\-02\-06 .INDENT 0.0 .IP \(bu 2 Fix deprecated imports from \fBwerkzeug\fP and \fBcollections\fP\&. .UNINDENT .SS Version 0.14.2 .sp Released 2017\-01\-10 .INDENT 0.0 .IP \(bu 2 Fix bug where \fBFlaskForm\fP assumed \fBmeta\fP argument was not \fBNone\fP if it was passed. \fI\%#278\fP .UNINDENT .SS Version 0.14.1 .sp Released 2017\-01\-10 .INDENT 0.0 .IP \(bu 2 Fix bug where the file validators would incorrectly identify an empty file as valid data. \fI\%#276\fP, \fI\%#277\fP .INDENT 2.0 .IP \(bu 2 \fBFileField\fP is no longer deprecated. The data is checked during processing and only set if it\(aqs a valid file. .IP \(bu 2 \fBhas_file\fP \fIis\fP deprecated; it\(aqs now equivalent to \fBbool(field.data)\fP\&. .IP \(bu 2 \fBFileRequired\fP and \fBFileAllowed\fP work with both the Flask\-WTF and WTForms \fBFileField\fP classes. .IP \(bu 2 The \fBOptional\fP validator now works with \fBFileField\fP\&. .UNINDENT .UNINDENT .SS Version 0.14 .sp Released 2017\-01\-06 .INDENT 0.0 .IP \(bu 2 Use ItsDangerous to sign CSRF tokens and check expiration instead of doing it ourselves. \fI\%#264\fP .INDENT 2.0 .IP \(bu 2 All tokens are URL safe, removing the \fBurl_safe\fP parameter from \fBgenerate_csrf\fP\&. \fI\%#206\fP .IP \(bu 2 All tokens store a timestamp, which is checked in \fBvalidate_csrf\fP\&. The \fBtime_limit\fP parameter of \fBgenerate_csrf\fP is removed. .UNINDENT .IP \(bu 2 Remove the \fBapp\fP attribute from \fBCsrfProtect\fP, use \fBcurrent_app\fP\&. \fI\%#264\fP .IP \(bu 2 \fBCsrfProtect\fP protects the \fBDELETE\fP method by default. \fI\%#264\fP .IP \(bu 2 The same CSRF token is generated for the lifetime of a request. It is exposed as \fBg.csrf_token\fP for use during testing. \fI\%#227\fP\fI\%#264\fP .IP \(bu 2 \fBCsrfProtect.error_handler\fP is deprecated. \fI\%#264\fP .INDENT 2.0 .IP \(bu 2 Handlers that return a response work in addition to those that raise an error. The behavior was not clear in previous docs. .IP \(bu 2 \fI\%#200\fP\fI\%#209\fP\fI\%#243\fP\fI\%#252\fP .UNINDENT .IP \(bu 2 Use \fBForm.Meta\fP instead of deprecated \fBSecureForm\fP for CSRF (and everything else). \fI\%#216\fP\fI\%#271\fP .INDENT 2.0 .IP \(bu 2 \fBcsrf_enabled\fP parameter is still recognized but deprecated. All other attributes and methods from \fBSecureForm\fP are removed. \fI\%#271\fP .UNINDENT .IP \(bu 2 Provide \fBWTF_CSRF_FIELD_NAME\fP to configure the name of the CSRF token. \fI\%#271\fP .IP \(bu 2 \fBvalidate_csrf\fP raises \fBwtforms.ValidationError\fP with specific messages instead of returning \fBTrue\fP or \fBFalse\fP\&. This breaks anything that was calling the method directly. \fI\%#239\fP\fI\%#271\fP .INDENT 2.0 .IP \(bu 2 CSRF errors are logged as well as raised. \fI\%#239\fP .UNINDENT .IP \(bu 2 \fBCsrfProtect\fP is renamed to \fBCSRFProtect\fP\&. A deprecation warning is issued when using the old name. \fBCsrfError\fP is renamed to \fBCSRFError\fP without deprecation. \fI\%#271\fP .IP \(bu 2 \fBFileField\fP is deprecated because it no longer provides functionality over the provided validators. Use \fBwtforms.FileField\fP directly. \fI\%#272\fP .UNINDENT .SS Version 0.13.1 .sp Released 2016\-10\-6 .INDENT 0.0 .IP \(bu 2 Deprecation warning for \fBForm\fP is shown during \fB__init__\fP instead of immediately when subclassing. \fI\%#262\fP .IP \(bu 2 Don\(aqt use \fBpkg_resources\fP to get version, for compatibility with GAE. \fI\%#261\fP .UNINDENT .SS Version 0.13 .sp Released 2016\-09\-29 .INDENT 0.0 .IP \(bu 2 \fBForm\fP is renamed to \fBFlaskForm\fP in order to avoid name collision with WTForms\(aqs base class. Using \fBForm\fP will show a deprecation warning. \fI\%#250\fP .IP \(bu 2 \fBhidden_tag\fP no longer wraps the hidden inputs in a hidden div. This is valid HTML5 and any modern HTML parser will behave correctly. \fI\%#193\fP\fI\%#217\fP .IP \(bu 2 \fBflask_wtf.html5\fP is deprecated. Import directly from \fBwtforms.fields.html5\fP\&. \fI\%#251\fP .IP \(bu 2 \fBis_submitted\fP is true for \fBPATCH\fP and \fBDELETE\fP in addition to \fBPOST\fP and \fBPUT\fP\&. \fI\%#187\fP .IP \(bu 2 \fBgenerate_csrf\fP takes a \fBtoken_key\fP parameter to specify the key stored in the session. \fI\%#206\fP .IP \(bu 2 \fBgenerate_csrf\fP takes a \fBurl_safe\fP parameter to allow the token to be used in URLs. \fI\%#206\fP .IP \(bu 2 \fBform.data\fP can be accessed multiple times without raising an exception. \fI\%#248\fP .IP \(bu 2 File extension with multiple parts (\fB\&.tar.gz\fP) can be used in the \fBFileAllowed\fP validator. \fI\%#201\fP .UNINDENT .SS Version 0.12 .sp Released 2015\-07\-09 .INDENT 0.0 .IP \(bu 2 Abstract \fBprotect_csrf()\fP into a separate method. .IP \(bu 2 Update reCAPTCHA configuration. .IP \(bu 2 Fix reCAPTCHA error handle. .UNINDENT .SS Version 0.11 .sp Released 2015\-01\-21 .INDENT 0.0 .IP \(bu 2 Use the new reCAPTCHA API. \fI\%#164\fP .UNINDENT .SS Version 0.10.3 .sp Released 2014\-11\-16 .INDENT 0.0 .IP \(bu 2 Add configuration: \fBWTF_CSRF_HEADERS\fP\&. \fI\%#159\fP .IP \(bu 2 Support customize hidden tags. \fI\%#150\fP .IP \(bu 2 And many more bug fixes. .UNINDENT .SS Version 0.10.2 .sp Released 2014\-09\-03 .INDENT 0.0 .IP \(bu 2 Update translation for reCaptcha. \fI\%#146\fP .UNINDENT .SS Version 0.10.1 .sp Released 2014\-08\-26 .INDENT 0.0 .IP \(bu 2 Update \fBRECAPTCHA_API_SERVER_URL\fP\&. \fI\%#145\fP .IP \(bu 2 Update requirement Werkzeug >= 0.9.5. .IP \(bu 2 Fix \fBCsrfProtect\fP exempt for blueprints. \fI\%#143\fP .UNINDENT .SS Version 0.10.0 .sp Released 2014\-07\-16 .INDENT 0.0 .IP \(bu 2 Add configuration: \fBWTF_CSRF_METHODS\fP\&. .IP \(bu 2 Support WTForms 2.0 now. .IP \(bu 2 Fix CSRF validation without time limit (\fBtime_limit=False\fP). .IP \(bu 2 \fBcsrf_exempt\fP supports blueprint. \fI\%#111\fP .UNINDENT .SS Version 0.9.5 .sp Released 2014\-03\-21 .INDENT 0.0 .IP \(bu 2 \fBcsrf_token\fP for all template types. \fI\%#112\fP .IP \(bu 2 Make \fBFileRequired\fP a subclass of \fBInputRequired\fP\&. \fI\%#108\fP .UNINDENT .SS Version 0.9.4 .sp Released 2013\-12\-20 .INDENT 0.0 .IP \(bu 2 Bugfix for \fBcsrf\fP module when form has a prefix. .IP \(bu 2 Compatible support for WTForms 2. .IP \(bu 2 Remove file API for \fBFileField\fP .UNINDENT .SS Version 0.9.3 .sp Released 2013\-10\-02 .INDENT 0.0 .IP \(bu 2 Fix validation of recaptcha when app in testing mode. \fI\%#89\fP .IP \(bu 2 Bugfix for \fBcsrf\fP module. \fI\%#91\fP .UNINDENT .SS Version 0.9.2 .sp Released 2013\-09\-11 .INDENT 0.0 .IP \(bu 2 Upgrade WTForms to 1.0.5. .IP \(bu 2 No lazy string for i18n. \fI\%#77\fP .IP \(bu 2 No \fBDateInput\fP widget in HTML5. \fI\%#81\fP .IP \(bu 2 \fBPUT\fP and \fBPATCH\fP for CSRF. \fI\%#86\fP .UNINDENT .SS Version 0.9.1 .sp Released 2013\-08\-21 .INDENT 0.0 .IP \(bu 2 Compatibility with Flask < 0.10. \fI\%#82\fP .UNINDENT .SS Version 0.9.0 .sp Released 2013\-08\-15 .INDENT 0.0 .IP \(bu 2 Add i18n support. \fI\%#65\fP .IP \(bu 2 Use default HTML5 widgets and fields provided by WTForms. .IP \(bu 2 Python 3.3+ support. .IP \(bu 2 Redesign form, replace \fBSessionSecureForm\fP\&. .IP \(bu 2 CSRF protection solution. .IP \(bu 2 Drop WTForms imports. .IP \(bu 2 Fix recaptcha i18n support. .IP \(bu 2 Fix recaptcha validator for Python 3. .IP \(bu 2 More test cases, it\(aqs 90%+ coverage now. .IP \(bu 2 Redesign documentation. .UNINDENT .SS Version 0.8.4 .sp Released 2013\-03\-28 .INDENT 0.0 .IP \(bu 2 Recaptcha Validator now returns provided message. \fI\%#66\fP .IP \(bu 2 Minor doc fixes. .IP \(bu 2 Fixed issue with tests barking because of nose/multiprocessing issue. .UNINDENT .SS Version 0.8.3 .sp Released 2013\-03\-13 .INDENT 0.0 .IP \(bu 2 Update documentation to indicate pending deprecation of WTForms namespace facade. .IP \(bu 2 PEP8 fixes. \fI\%#64\fP .IP \(bu 2 Fix Recaptcha widget. \fI\%#49\fP .UNINDENT .SS Version 0.8.2 and prior .sp Initial development by Dan Jacob and Ron Duplain. .SS How to contribute to Flask\-WTF .sp Thank you for considering contributing to Flask\-WTF! .SS Support questions .sp Please don\(aqt use the issue tracker for this. The issue tracker is a tool to address bugs and feature requests in Flask\-WTF itself. Use one of the following resources for questions about using Flask\-WTF or issues with your own code: .INDENT 0.0 .IP \(bu 2 The \fB#get\-help\fP channel on our Discord chat: \fI\%https://discord.gg/pallets\fP .IP \(bu 2 The mailing list \fI\%flask@python.org\fP for long term discussion or larger issues. .IP \(bu 2 Ask on \fI\%Stack Overflow\fP\&. Search with Google first using: \fBsite:stackoverflow.com flask\-wtf {search term, exception message, etc.}\fP .UNINDENT .SS Reporting issues .sp Include the following information in your post: .INDENT 0.0 .IP \(bu 2 Describe what you expected to happen. .IP \(bu 2 If possible, include a \fI\%minimal reproducible example\fP to help us identify the issue. This also helps check that the issue is not with your own code. .IP \(bu 2 Describe what actually happened. Include the full traceback if there was an exception. .IP \(bu 2 List your Python, Flask\-WTF, and WTForms versions. If possible, check if this issue is already fixed in the latest releases or the latest code in the repository. .UNINDENT .SS Submitting patches .sp If there is not an open issue for what you want to submit, prefer opening one for discussion before working on a PR. You can work on any issue that doesn\(aqt have an open PR linked to it or a maintainer assigned to it. These show up in the sidebar. No need to ask if you can work on an issue that interests you. .sp Include the following in your patch: .INDENT 0.0 .IP \(bu 2 Use \fI\%Black\fP to format your code. This and other tools will run automatically if you install \fI\%pre\-commit\fP using the instructions below. .IP \(bu 2 Include tests if your patch adds or changes code. Make sure the test fails without your patch. .IP \(bu 2 Update any relevant docs pages and docstrings. Docs pages and docstrings should be wrapped at 72 characters. .IP \(bu 2 Add an entry in \fBCHANGES.rst\fP\&. Use the same style as other entries. Also include \fB\&.. versionchanged::\fP inline changelogs in relevant docstrings. .UNINDENT .SS First time setup .INDENT 0.0 .IP \(bu 2 Download and install the \fI\%latest version of git\fP\&. .IP \(bu 2 Configure git with your \fI\%username\fP and \fI\%email\fP\&. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ git config \-\-global user.name \(aqyour name\(aq $ git config \-\-global user.email \(aqyour email\(aq .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Make sure you have a \fI\%GitHub account\fP\&. .IP \(bu 2 Fork Flask\-WTF to your GitHub account by clicking the \fI\%Fork\fP button. .IP \(bu 2 \fI\%Clone\fP the main repository locally. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ git clone https://github.com/wtforms/flask\-wtf $ cd flask\-wtf .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Add your fork as a remote to push your work to. Replace \fB{username}\fP with your username. This names the remote \(dqfork\(dq, the default WTForms remote is \(dqorigin\(dq. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ git remote add fork https://github.com/{username}/flask\-wtf .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Create a virtualenv. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ python3 \-m venv env $ . env/bin/activate .ft P .fi .UNINDENT .UNINDENT .sp On Windows, activating is different. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C > env\eScripts\eactivate .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Upgrade pip and setuptools. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ python \-m pip install \-\-upgrade pip setuptools .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Install the development dependencies, then install Flask\-WTF in editable mode. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ pip install \-r requirements/dev.txt && pip install \-e . .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Install the pre\-commit hooks. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ pre\-commit install .ft P .fi .UNINDENT .UNINDENT .UNINDENT .SS Start coding .INDENT 0.0 .IP \(bu 2 Create a branch to identify the issue you would like to work on. If you\(aqre submitting a bug or documentation fix, branch off of the latest \(dq.x\(dq branch. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ git fetch origin $ git checkout \-b your\-branch\-name origin/1.0.x .ft P .fi .UNINDENT .UNINDENT .sp If you\(aqre submitting a feature addition or change, branch off of the \(dqmain\(dq branch. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ git fetch origin $ git checkout \-b your\-branch\-name origin/main .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Using your favorite editor, make your changes, \fI\%committing as you go\fP\&. .IP \(bu 2 Include tests that cover any code changes you make. Make sure the test fails without your patch. Run the tests as described below. .IP \(bu 2 Push your commits to your fork on GitHub and \fI\%create a pull request\fP\&. Link to the issue being addressed with \fBfixes #123\fP in the pull request. .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ git push \-\-set\-upstream fork your\-branch\-name .ft P .fi .UNINDENT .UNINDENT .UNINDENT .SS Running the tests .sp Run the basic test suite with pytest. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ pytest .ft P .fi .UNINDENT .UNINDENT .sp This runs the tests for the current environment, which is usually sufficient. CI will run the full suite when you submit your pull request. You can run the full test suite with tox if you don\(aqt want to wait. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ tox .ft P .fi .UNINDENT .UNINDENT .SS Running test coverage .sp Generating a report of lines that do not have test coverage can indicate where to start contributing. Run \fBpytest\fP using \fBcoverage\fP and generate a report. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ pip install coverage $ coverage run \-m pytest $ coverage html .ft P .fi .UNINDENT .UNINDENT .sp Open \fBhtmlcov/index.html\fP in your browser to explore the report. .sp Read more about \fI\%coverage\fP\&. .SS Building the docs .sp Build the docs in the \fBdocs\fP directory using Sphinx. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ cd docs $ make html .ft P .fi .UNINDENT .UNINDENT .sp Open \fB_build/html/index.html\fP in your browser to view the docs. .sp Read more about \fI\%Sphinx\fP\&. .SH AUTHOR WTForms .SH COPYRIGHT 2024 WTForms .\" Generated by docutils manpage writer. .