File: form.rst

package info (click to toggle)
flask-wtf 1.2.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 428 kB
  • sloc: python: 1,313; makefile: 22; sh: 10
file content (185 lines) | stat: -rw-r--r-- 5,817 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
Creating Forms
==============

Secure Form
-----------

.. currentmodule:: flask_wtf

Without any configuration, the :class:`FlaskForm` will be a session secure
form with csrf protection. We encourage you not to change this.

But if you want to disable the csrf protection, you can pass::

    form = FlaskForm(meta={'csrf': False})

You can disable it globally—though you really shouldn't—with the
configuration::

    WTF_CSRF_ENABLED = False

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::

    WTF_CSRF_SECRET_KEY = 'a random string'


File Uploads
------------

.. currentmodule:: flask_wtf.file

The :class:`FileField` provided by Flask-WTF differs from the WTForms-provided
field. It will check that the file is a non-empty instance of
:class:`~werkzeug.datastructures.FileStorage`, otherwise ``data`` will be
``None``. ::

    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('/upload', methods=['GET', 'POST'])
    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, 'photos', filename
            ))
            return redirect(url_for('index'))

        return render_template('upload.html', form=form)


Similarly, you can use the :class:`MultipleFileField` provided by Flask-WTF
to handle multiple files. It will check that the files is a list of non-empty instance of
:class:`~werkzeug.datastructures.FileStorage`, otherwise ``data`` will be
``None``. ::

    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('/upload', methods=['GET', 'POST'])
    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, 'photos', filename
                ))
            return redirect(url_for('index'))

        return render_template('upload.html', form=form)


Remember to set the ``enctype`` of the HTML form to
``multipart/form-data``, otherwise ``request.files`` will be empty.

.. sourcecode:: html

    <form method="POST" enctype="multipart/form-data">
        ...
    </form>

Flask-WTF handles passing form data to the form for you.
If you pass in the data explicitly, remember that ``request.form`` must
be combined with ``request.files`` for the form to see the file data. ::

    form = PhotoForm()
    # is equivalent to:

    from flask import request
    from werkzeug.datastructures import CombinedMultiDict
    form = PhotoForm(CombinedMultiDict((request.files, request.form)))


Validation
~~~~~~~~~~

Flask-WTF supports validating file uploads with
:class:`FileRequired`, :class:`FileAllowed`, and :class:`FileSize`. They
can be used with both Flask-WTF's and WTForms's ``FileField`` and
``MultipleFileField`` classes.

:class:`FileAllowed` works well with Flask-Uploads. ::

    from flask_uploads import UploadSet, IMAGES
    from flask_wtf import FlaskForm
    from flask_wtf.file import FileField, FileAllowed, FileRequired

    images = UploadSet('images', IMAGES)

    class UploadForm(FlaskForm):
        upload = FileField('image', validators=[
            FileRequired(),
            FileAllowed(images, 'Images only!')
        ])

It can be used without Flask-Uploads by passing the extensions directly. ::

    class UploadForm(FlaskForm):
        upload = FileField('image', validators=[
            FileRequired(),
            FileAllowed(['jpg', 'png'], 'Images only!')
        ])


.. _recaptcha:

Recaptcha
---------

.. currentmodule:: flask_wtf.recaptcha

Flask-WTF also provides Recaptcha support through a :class:`RecaptchaField`::

    from flask_wtf import FlaskForm, RecaptchaField
    from wtforms import TextField

    class SignupForm(FlaskForm):
        username = TextField('Username')
        recaptcha = RecaptchaField()

This comes with a number of configuration variables, some of which you have to configure.

======================= ==============================================
RECAPTCHA_PUBLIC_KEY    **required** A public key.
RECAPTCHA_PRIVATE_KEY   **required** A private key.
RECAPTCHA_API_SERVER    **optional** Specify your Recaptcha API server.
RECAPTCHA_PARAMETERS    **optional** A dict of JavaScript (api.js) parameters.
RECAPTCHA_DATA_ATTRS    **optional** A dict of data attributes options.
                        https://developers.google.com/recaptcha/docs/display#javascript_resource_apijs_parameters
======================= ==============================================

Example of RECAPTCHA_PARAMETERS, and RECAPTCHA_DATA_ATTRS::

    RECAPTCHA_PARAMETERS = {'hl': 'zh', 'render': 'explicit'}
    RECAPTCHA_DATA_ATTRS = {'theme': 'dark'}

For your convenience, when testing your application, if ``app.testing`` is ``True``, the recaptcha
field will always be valid.

And it can be easily setup in the templates:

.. sourcecode:: html+jinja

    <form action="/" method="post">
        {{ form.username }}
        {{ form.recaptcha }}
    </form>

We have an example for you: `recaptcha@github`_.

.. _`recaptcha@github`: https://github.com/pallets-eco/flask-wtf/tree/main/examples/recaptcha