File: multipart.rst

package info (click to toggle)
python-falcon 4.0.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,172 kB
  • sloc: python: 33,608; javascript: 92; sh: 50; makefile: 50
file content (167 lines) | stat: -rw-r--r-- 5,464 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
.. _multipart:

Multipart Forms
===============

Falcon features easy and efficient access to submitted multipart forms by using
:class:`~falcon.media.MultipartFormHandler` to handle the
``multipart/form-data`` :ref:`media <media>` type. This handler is enabled by
default, allowing you to use ``req.get_media()`` to iterate over the
:class:`body parts <falcon.media.multipart.BodyPart>` in a form:

.. tab-set::

    .. tab-item:: WSGI
        :sync: wsgi

        .. code:: python

            form = req.get_media()
            for part in form:
                if part.content_type == 'application/json':
                    # Body part is a JSON document, do something useful with it
                    resp.media = part.get_media()
                elif part.name == 'datafile':
                    while True:
                        # Do something with the uploaded data (file)
                        chunk = part.stream.read(8192)
                        if not chunk:
                            break
                        feed_data(chunk)
                elif part.name == 'imagedata':
                    # Store this body part in a file.
                    filename = os.path.join(UPLOAD_PATH, part.secure_filename)
                    with open(filename, 'wb') as dest:
                        part.stream.pipe(dest)
                else:
                    # Do something else
                    form_data[part.name] = part.text

    .. tab-item:: ASGI
        :sync: asgi

        .. code:: python

            form = await req.get_media()
            async for part in form:
                if part.content_type == 'application/json':
                    # Body part is a JSON document, do something useful with it
                    resp.media = await part.get_media()
                elif part.name == 'datafile':
                    # Do something with the uploaded data (file)
                    async for chunk in part.stream:
                        await feed_data(chunk)
                elif part.name == 'imagedata':
                    # Store this body part in a file.
                    filename = os.path.join(UPLOAD_PATH, part.secure_filename)
                    async with aiofiles.open(filename, 'wb') as dest:
                        await part.stream.pipe(dest)
                else:
                    # Do something else
                    form_data[part.name] = await part.text

.. note::
   Rather than being read in and buffered all at once, the request stream is
   only consumed on-demand, while iterating over the body parts in the form.

   For each part, you can choose whether to read the whole part into memory,
   write it out to a file, or :ref:`upload it to the cloud
   <multipart_cloud_upload>`. Falcon offers straightforward support for all
   of these scenarios.

Multipart Form and Body Part Types
----------------------------------

.. tab-set::

    .. tab-item:: WSGI
        :sync: wsgi

        .. autoclass:: falcon.media.multipart.MultipartForm
            :members:

        .. autoclass:: falcon.media.multipart.BodyPart
            :members:

    .. tab-item:: ASGI
        :sync: asgi

        .. autoclass:: falcon.asgi.multipart.MultipartForm
            :members:

        .. autoclass:: falcon.asgi.multipart.BodyPart
            :members:

.. _multipart_parser_conf:

Parser Configuration
--------------------

Similar to :class:`falcon.App`\'s :attr:`~falcon.App.req_options` and
:attr:`~falcon.App.resp_options`, instantiating a
:class:`~falcon.media.MultipartFormHandler` also fills its
:attr:`~falcon.media.MultipartFormHandler.parse_options` attribute with a set
of sane default values suitable for many use cases out of the box. If you need
to customize certain form parsing aspects of your application, the preferred
way is to directly modify the properties of this attribute on the media handler
(parser) in question:

.. code:: python

    import falcon
    import falcon.media

    handler = falcon.media.MultipartFormHandler()

    # Assume text fields to be encoded in latin-1 instead of utf-8
    handler.parse_options.default_charset = 'latin-1'

    # Allow an unlimited number of body parts in the form
    handler.parse_options.max_body_part_count = 0

    # Afford parsing msgpack-encoded body parts directly via part.get_media()
    extra_handlers = {
        falcon.MEDIA_MSGPACK: falcon.media.MessagePackHandler(),
    }
    handler.parse_options.media_handlers.update(extra_handlers)

In order to use your customized handler in an app, simply replace the default
handler for ``multipart/form-data`` with the new one:

.. tab-set::

    .. tab-item:: WSGI
        :sync: wsgi

        .. code:: python

            app = falcon.App()

            # handler is instantiated and configured as per the above snippet
            app.req_options.media_handlers[falcon.MEDIA_MULTIPART] = handler

    .. tab-item:: ASGI
        :sync: asgi

        .. code:: python

            app = falcon.asgi.App()

            # handler is instantiated and configured as per the above snippet
            app.req_options.media_handlers[falcon.MEDIA_MULTIPART] = handler

.. tip::
    For more information on customizing media handlers, see also:
    :ref:`custom_media_handlers`.

Parsing Options
---------------

.. autoclass:: falcon.media.multipart.MultipartParseOptions
    :members:

Parsing Errors
--------------

.. autoclass:: falcon.MultipartParseError
    :members: